///////////////////////////////////////////////////////////
// AyaFile.cs
// Implementation of Class AyaFile
// CSLA type: Editable Root
// Created on: 30-Rocktober-2008
// Object design: John
// Coded: 30-Rocktober-2008
///////////////////////////////////////////////////////////
using System;
using System.Data;
using CSLA.Data;
using GZTW.Data;
using CSLA;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Collections.Generic;
//case 73
namespace GZTW.AyaNova.BLL
{
///
/// AyaFile object
/// Storage, retrieval and deletion of files inside
/// the AyaNova database.
///
/// Automatic compression / decompression.
///
/// NOTE: There is a 50MB source file size limit
///
[Serializable]
public class AyaFile : BusinessBase
{
#region Attributes
private Guid mID;
private SmartDate mCreated;
private SmartDate mModified;
private Guid mCreator;
private Guid mModifier;
private Guid mRootObjectID = Guid.Empty;
private RootObjectTypes mRootObjectType;
private AyaFileType mFileType;
private string mName = null;
private byte[] mContent=null;
private bool bReadOnly = false;
private int mFileSize;
private int mFileSizeStored;
#endregion
#region Constructor
///
/// Private constructor to prevent direct instantiation
///
private AyaFile()
{
//New ID
mID = Guid.NewGuid();
//Set record history to defaults
mCreated = new SmartDate(DBUtil.CurrentWorkingDateTime);
mModified = new SmartDate();
mCreator = Guid.Empty;
mModifier = Guid.Empty;
//pre-break various rules
Name = "";
RootObjectID = Guid.Empty;
RootObjectType = RootObjectTypes.Nothing;
mFileType = AyaFileType.WikiFile;
mFileSize = 0;
}
#endregion
#region Business properties
///
/// Internal Unique GUID value of AyaFile record in database
///
public Guid ID
{
get
{
return mID;
}
}
///
/// Get created date
///
///
///
public string Created
{
get
{
return mCreated.ToString();
}
}
///
/// Get modified date
///
///
///
public string Modified
{
get
{
return mModified.ToString();
}
}
///
/// Get user record ID of person who created this record
///
///
///
public Guid Creator
{
get
{
return mCreator;
}
}
///
/// Get user ID of person who modified this record
///
///
///
public Guid Modifier
{
get
{
return mModifier;
}
}
///
/// AyaNova object ID
///
public Guid RootObjectID
{
get
{
return mRootObjectID;
}
set
{
if (bReadOnly)
ThrowSetError();
else
{
if (mRootObjectID != value)
{
mRootObjectID = value;
BrokenRules.Assert("RootObjectID", "Error.Object.RequiredFieldEmpty,AyaFile.Label.RootObjectID", "RootObjectID", value == Guid.Empty);
MarkDirty();
}
}
}
}
///
/// AyaNova object type
///
public RootObjectTypes RootObjectType
{
get
{
return mRootObjectType;
}
set
{
if (bReadOnly)
ThrowSetError();
else
{
if (mRootObjectType != value)
{
mRootObjectType = value;
BrokenRules.Assert("RootObjectType", "Error.Object.RequiredFieldEmpty,AyaFile.Label.RootObjectType", "RootObjectType", value == RootObjectTypes.Nothing);
MarkDirty();
}
}
}
}
///
/// AyaNova file type
///
public AyaFileType FileType
{
get
{
return mFileType;
}
set
{
if (bReadOnly)
ThrowSetError();
else
{
if (mFileType != value)
{
mFileType = value;
//BrokenRules.Assert("FileType", "Error.Object.RequiredFieldEmpty,AyaFile.Label.FileType", "FileType", value == RootObjectTypes.Nothing);
MarkDirty();
}
}
}
}
///
/// File name displayed on wiki page and potentially in pick lists
/// combo boxes
///
/// This is a required field 1-255 Unicode characters and must be a legal file name
///
public string Name
{
get
{
return mName;
}
set
{
if (bReadOnly)
ThrowSetError();
else
{
if (mName != value)
{
mName = value;
BrokenRules.Assert("NameRequired",
"Error.Object.RequiredFieldEmpty,AyaFile.Label.Name",
"Name", value.Length == 0);
BrokenRules.Assert("NameLength",
"Error.Object.FieldLengthExceeded255,AyaFile.Label.Name",
"Name", value.Length > 255);
MarkDirty();
}
}
}
}
///
/// Size of file in bytes
/// (Note: *file* size, not the amount of bytes actually
/// stored in the database which is compressed)
///
public int FileSize
{
get
{
return this.mFileSize;
}
}
///
/// Size of stored file in bytes
/// (Note: *file* size stored in database after compression)
///
public int FileSizeStored
{
get
{
return this.mFileSize;
}
}
///
/// Returns content of AyaFile as a
///
///
public System.IO.MemoryStream GetContent()
{
if (mContent.Length == mFileSize)//it's not compressed so just return it
return new System.IO.MemoryStream(mContent);
else//it *is* compressed so decompress and return
return new System.IO.MemoryStream(AyaBizUtils.Decompress(mContent));
}
///
/// Set the content from a
/// Must be less bytes than limit set in
/// or 50mb (hard coded limit) whichever is smaller
///
///
public void SetContent(System.IO.Stream mStream)
{
//is file size larger than admin set value or default 50mb limit?
long limit=AyaBizUtils.GlobalSettings.MaxFileSizeMB * 1048576;
if(limit > 52428800) limit = 52428800;
if (mStream.Length > limit)
{
throw new AyAyaFileTooLargeException(string.Format(LocalizedTextTable.GetLocalizedTextDirect("AyaFile.Error.FileTooLarge"),
AyaBizUtils.FileSizeDisplay(limit)));
}
mFileSize = (int)mStream.Length;
mStream.Position = 0;
byte[] bData = new byte[mStream.Length];
mStream.Read(bData, 0, (int)mStream.Length);
mContent = AyaBizUtils.Compress(bData);
//did it compress smaller?
//don't want to store uncompressible files that are actually larger after compression
if (mContent.Length >= mFileSize)
{
//yup, it's bigger compressed, so store the uncompressed version instead
mContent = bData;
}
MarkDirty();
}
///
/// Byte array set content
///
///
public void SetContent(byte[] bData)
{
//is file size larger than admin set value or default 50mb limit?
long limit = AyaBizUtils.GlobalSettings.MaxFileSizeMB * 1048576;
if (limit > 52428800) limit = 52428800;
if (bData.LongLength > limit)
{
throw new AyAyaFileTooLargeException(string.Format(LocalizedTextTable.GetLocalizedTextDirect("AyaFile.Error.FileTooLarge"),
AyaBizUtils.FileSizeDisplay(limit)));
}
mFileSize = (int)bData.LongLength;
//mStream.Position = 0;
//byte[] bData = new byte[mStream.Length];
//mStream.Read(bData, 0, (int)mStream.Length);
mContent = AyaBizUtils.Compress(bData);
//did it compress smaller?
//don't want to store uncompressible files that are actually larger after compression
if (mContent.Length >= mFileSize)
{
//yup, it's bigger compressed, so store the uncompressed version instead
mContent = bData;
}
MarkDirty();
}
///
/// Write file to disk
///
/// Path to save to
/// Optionally force file name or use original if not specified
public string WriteToDisk(string sPath, string sName)
{
System.IO.FileStream fileStream = null;
sPath = sPath.Trim();
if (sPath[sPath.Length-1] != Path.DirectorySeparatorChar)
sPath += Path.DirectorySeparatorChar;
if (string.IsNullOrEmpty(sName))
{
sPath += mName;
}
else
sPath += sName;
try
{
fileStream = System.IO.File.Create(sPath);
//TESTING ONLY
//mFileSize = mContent.Length;
if (mContent.Length == mFileSize)//not compressed?
{
fileStream.Write(mContent, 0, mContent.Length);
fileStream.Close();
}
else
{
byte[] b = AyaBizUtils.Decompress(mContent);
fileStream.Write(b, 0, b.Length);
fileStream.Close();
}
}
finally
{
fileStream.Dispose();
}
return sPath;
}
///
/// Get the MIME type for this file based on extension
///
public string mimeType
{
get {
return AyaMimeTypeMap.GetMimeType(System.IO.Path.GetExtension(mName));
}
}
///
/// Throw an error when a read only user
/// tries to set a property
/// (this should normally never be called unless someone is using the developer api since the UI
/// should prevent it from happening initially)
///
private void ThrowSetError()
{
throw new System.Security.SecurityException
(
string.Format
(
LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToChange"),
LocalizedTextTable.GetLocalizedTextDirect("O.AyaFile")
)
);
}
#endregion
#region System.object overrides
///
///
///
///
public override string ToString()
{
return "AyaFile" + mID.ToString();
}
///
///
public override bool Equals(Object obj)
{
if (obj == null || GetType() != obj.GetType()) return false;
AyaFile c = (AyaFile)obj;
return mID == c.mID;
}
///
///
///
///
public override int GetHashCode()
{
return ("AyaFile" + mID).GetHashCode();
}
#endregion
#region Static methods
///
/// Create new AyaFile
///
/// Empty AyaFile object
public static AyaFile NewItem()
{
AyaFile c;
if (AyaBizUtils.Right("Object.AyaFile") > (int)SecurityLevelTypes.ReadOnly)
{
c = new AyaFile();
return c;
}
else
throw new System.Security.SecurityException(
string.Format(
LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToCreate"),
LocalizedTextTable.GetLocalizedTextDirect("O.AyaFile")));
}
///
/// Fetch existing AyaFile
///
/// AyaFile
/// AyaFile Guid
public static AyaFile GetItem(Guid ID)
{
return (AyaFile)DataPortal.Fetch(new Criteria(ID,Guid.Empty));
}
///
/// Delete AyaFile
///
/// AyaFile applicationID
public static void DeleteItem(Guid ID)
{
DataPortal.Delete(new Criteria(ID, Guid.Empty));
}
///
/// Delete all files that are embedded images in wiki page
///
/// WikiPage ID
public static void DeleteAllEmbeddedImagesInWikiPage(Guid WikiPageID)
{
DataPortal.Delete(new Criteria(Guid.Empty, WikiPageID));
}
///
/// Same as WriteFileToDisk but fetches AyaFile first
/// returns the full path and name it was actually saved to
///
///
///
///
public static string GetAndWriteFileToDisk(Guid ID, string sPath, string sName)
{
AyaFile af = AyaFile.GetItem(ID);
return af.WriteToDisk(sPath, sName);
}
///
/// User can read AyaFiles?
///
public static bool CanRead
{
get
{
return (AyaBizUtils.Right("Object.AyaFile") > (int)SecurityLevelTypes.NoAccess);
}
}
///
/// User can write AyaFiles?
/// (anything above read only is considered full rights to edit, upload and delete files)
///
public static bool CanWrite
{
get
{
return (AyaBizUtils.Right("Object.AyaFile") > (int)SecurityLevelTypes.ReadOnly);
}
}
///
/// Retrieve internal ID from name.
///
///
/// Text value
/// Guid ID value or Guid.Empty if no match
public static Guid GetIDFromName(string Name)
{
return GuidFetcher.GetItem("AFILE", "ANAME", Name);
}
#endregion
#region DAL DATA ACCESS
#region Fetch
///
///
protected override void DataPortal_Fetch(object Criteria)
{
Criteria crit = (Criteria)Criteria;
SafeDataReader dr = null;
try
{
dr = DBUtil.GetReaderFromSQLString("SELECT * FROM aFile WHERE aID=@ID;", crit.ID);
if (!dr.Read())
DBUtil.ThrowFetchError("AyaFile ID: " + crit.ID.ToString());
//Standard fields
mID = dr.GetGuid("aID");
mCreated = DBUtil.ToLocal(dr.GetSmartDate("aCreated"));
mModified = DBUtil.ToLocal(dr.GetSmartDate("aModified"));
mCreator = dr.GetGuid("aCreator");
mModifier = dr.GetGuid("aModifier");
//AyaFile fields
Name = dr.GetString("aName");
mFileSize = dr.GetInt32("AFileSize");
RootObjectID = dr.GetGuid("aRootObjectID");
RootObjectType = (RootObjectTypes)dr.GetInt16("aRootObjectType");
FileType = (AyaFileType)dr.GetInt16("aFileType");
//Get the FObject
//Get the data's size
mFileSizeStored = dr.GetInt32("aFObjectSize");
//allocate a place to store it
mContent = new Byte[mFileSizeStored];
//retrieve the (compressed) bytes
dr.GetBytes("aFObject", 0, mContent, 0, mContent.Length);
if(dr!=null) dr.Close();
}
finally
{
if (dr != null) dr.Close();
}
MarkOld();
//Get access rights level
bReadOnly = AyaBizUtils.Right("Object.AyaFile") < (int)SecurityLevelTypes.ReadWrite;
}
#endregion fetch
#region Update
///
/// Called by DataPortal to delete/add/update data into the database
///
protected override void DataPortal_Update()
{
// If not a new record, check if record was modified
//by another user since original retrieval:
if (!IsNew)
DBUtil.CheckSafeToUpdate(this.mModified.Date, this.mID, "aFile");
#region Delete
if (IsDeleted)
{
throw new System.NotSupportedException("AyaFile->Update->Delete: not supported for this object, call the static/shared AyaFile.DeleteItem() method instead");
}
#endregion
#region Add / Update
//get modification time temporarily, if update succeeds then
//set to this time
System.DateTime dtModified = DBUtil.CurrentWorkingDateTime;
DBCommandWrapper cm = null;
if (IsNew)//Add or update?
cm = DBUtil.GetCommandFromSQL(
"INSERT INTO aFile (aID, aCreated,aModified,aCreator,aModifier, " +
"aRootObjectID, aRootObjectType, aFileType, aName, aFileSize, aFObject,aFObjectSize) " +
"VALUES (@ID,@Created,@Modified,@CurrentUserID,@CurrentUserID, " +
"@RootObjectID,@RootObjectType, @FileType, @Name,@FileSize,@FObject,@FObjectSize)"
);
else
cm = DBUtil.GetCommandFromSQL(
"UPDATE aFile SET aID=@ID, " +
"aModified=@Modified,aModifier=@CurrentUserID, " +
"aRootObjectID=@RootObjectID,aRootObjectType=@RootObjectType, aFileType=@FileType, aName=@Name, " +
"aFileSize=@FileSize, aFObject=@FObject,aFObjectSize=@FObjectSize " +
"WHERE aID=@ID"
);
//AyaFile fields
cm.AddInParameter("@ID", DbType.Guid, mID);
cm.AddInParameter("@Name", DbType.String, mName);
cm.AddInParameter("@RootObjectID", DbType.Guid, mRootObjectID);
cm.AddInParameter("@RootObjectType", DbType.Int16, (int)mRootObjectType);
cm.AddInParameter("@Filetype", DbType.Int16, (int)mFileType);
cm.AddInParameter("@FileSize", DbType.Int32, mFileSize);
//Standard fields
cm.AddInParameter("@CurrentUserID", DbType.Guid, CurrentUserID);
cm.AddInParameter("@Created", DbType.DateTime, DBUtil.ToUTC(mCreated).DBValue);
cm.AddInParameter("@Modified", DbType.DateTime, DBUtil.ToUTC(dtModified));
cm.AddInParameter("@FObject", DbType.Object, mContent);
cm.AddInParameter("@FObjectSize", DbType.Int32, mContent.GetLength(0));
using (IDbConnection connection = DBUtil.DB.GetConnection())
{
connection.Open();
IDbTransaction transaction = connection.BeginTransaction();
try
{
DBUtil.DB.ExecuteNonQuery(cm, transaction);
MarkOld();//db is now synched with object
// Commit the transaction
transaction.Commit();
}
catch
{
// Rollback transaction
transaction.Rollback();
throw;
}
finally
{
connection.Close();
}
//Successful update so
//change modification time to match
this.mModified.Date = dtModified;
}
#endregion
}
#endregion update
#region Delete
///
/// Remove a AyaFile record
///
///
protected override void DataPortal_Delete(object Criteria)
{
Criteria crit = (Criteria)Criteria;
DBCommandWrapper cmDelete = null;
//Delete *all* embedded images from a wiki page?
if (crit.WikiPageID != Guid.Empty)
{
cmDelete = DBUtil.GetCommandFromSQL("DELETE FROM aFile WHERE aRootObjectID = @ID AND aFileType=1");
cmDelete.AddInParameter("@ID", DbType.Guid, crit.WikiPageID);
}
else
{
//Delete object
cmDelete = DBUtil.GetCommandFromSQL("DELETE FROM aFile WHERE aID = @ID;");
cmDelete.AddInParameter("@ID", DbType.Guid, crit.ID);
}
using (IDbConnection connection = DBUtil.DB.GetConnection())
{
connection.Open();
IDbTransaction transaction = connection.BeginTransaction();
try
{
DBUtil.DB.ExecuteNonQuery(cmDelete, transaction);
// Commit the transaction
transaction.Commit();
}
catch
{
// Rollback transaction
transaction.Rollback();
throw;
}
finally
{
connection.Close();
}
}
}
#endregion delete
#endregion
#region Override IsValid / IsDirty
///
///
///
public override bool IsValid
{
get
{
return base.IsValid ;
}
}
///
///
///
public override bool IsDirty
{
get
{
return base.IsDirty ;
}
}
#endregion
#region criteria
///
/// Criteria for identifying existing object
///
[Serializable]
private class Criteria
{
public Guid ID;
public Guid WikiPageID;
public Criteria(Guid _ID, Guid _WikiPageID)
{
ID = _ID;
WikiPageID = _WikiPageID;
}
}
#endregion
}//end AyaFile
}//end namespace GZTW.AyaNova.BLL