using System; using System.Collections.Generic; using System.Data; using System.Data.Entity; using System.Data.SqlClient; using System.IO; using System.Linq; using System.Net; using System.Xml.Linq; using Neo.Afx.ComponentModel; using Neo.Afx.Services.Documents.Entities; using Neo.Afx.Services.Audits; namespace Neo.Afx.Services.Documents { // TODO: TWR - Fix KVP results and remove try..catch's /// /// The documents database /// public partial class DocumentsDatabase : Database { const string DefaultMimeType = "application/octet-stream"; const int ItemNumberWidth = 7; // used to pad ItemID /// /// Initializes a new instance of the class. /// public DocumentsDatabase() : base(new DocumentContext()) { } #region UploadFile /// /// Uploads the file. /// /// The uploaded by ID. /// The NT account name of the user. /// The document ID. /// The entity ID. /// The item ID. /// The document type ID. /// The document store location ID. /// Name of the file. /// Type of the content. /// The content. /// public Document UploadFile(long uploadedByID, string uploadedByUserName, long documentID, int entityID, long itemID, short documentTypeID, long documentStoreLocationID, string fileName, string contentType, byte[] content) { var location = GetDocumentStoreLocation(documentStoreLocationID); if(location == null) { throw new ArgumentOutOfRangeException("documentStoreLocationID", "Invalid document store location ID"); } var mimeType = GetDocumentMimeType(contentType); if(mimeType == null) { throw new ArgumentOutOfRangeException("contentType", "The file mime type is not supported by the file store."); } Document document; if(documentID > 0) { document = GetDocuments(entityID, itemID).FirstOrDefault(d => d.DocumentID == documentID); } else { document = GetDocuments(entityID, itemID).FirstOrDefault(d => d.Description.ToLower() == fileName.ToLower() && d.DocumentTypeID == documentTypeID && d.DocumentStoreLocationID == documentStoreLocationID); } if(document != null) { document.UpdatedByID = uploadedByID; document.UpdatedDate = DateTime.Now; document.Description = fileName; document.DocumentMimeTypeID = mimeType.DocumentMimeTypeID; document.DocumentVerificationStatusID = 1; /*change status to awaiting verifition as a new document is being added*/ Update(document); Save(); Upload(document, uploadedByUserName, content); } else { if(documentID == -1) { var documentType = GetDocumentType(documentTypeID); document = new Document { IsCancelled = false, CreatedByID = uploadedByID, CreatedDate = DateTime.Now, EntityID = entityID, ItemID = itemID, DocumentTypeID = documentTypeID, DocumentStoreLocationID = location.DocumentStoreLocationID, DocumentMimeTypeID = mimeType.DocumentMimeTypeID, Title = documentType.Description, Description = fileName, UpdatedByID = uploadedByID, UpdatedDate = DateTime.Now, DocumentVerificationStatusID = 1 /*default status to awaiting verification*/ }; Insert(document); Save(); Upload(document, uploadedByUserName, content); } } var auditDb = new AuditsDatabase(); auditDb.WriteEntry(uploadedByID, "Application", "Updated", "Uploaded document " + fileName, false, false, entityID, itemID); return document; } #endregion #region GetDocument /// /// Gets the document. /// /// The document ID. /// public Document GetDocument(long documentID) { return GetByID(documentID); } #endregion #region GetDocumentStores /// /// Gets the document stores. /// /// The document ID. /// public IEnumerable GetDocumentStores(long documentID) { return from q in Context.DocumentStores.Include("Document") where q.DocumentID == documentID select q; } #endregion #region UpdateDocumentItemID /// /// Updates the document item ID. /// /// The updated by ID. /// The entity ID. /// The old item ID. /// The new item ID. /// public void UpdateDocumentItemID(long updatedByID, long entityID, long oldItemID, long newItemID) { var document = Get(d => d.EntityID == entityID && d.ItemID == oldItemID, null, "DocumentStoreLocation").FirstOrDefault(); if(document == null) { return; } Context.Database.ExecuteSqlCommand("UPDATE Doc.Documents SET ItemID=@p0, UpdatedByID=@p1, UpdatedDate=GETDATE() WHERE EntityID=@p2 AND ItemID=@p3", newItemID, updatedByID, entityID, oldItemID); } #endregion #region Delete /// /// Deletes the document with the specified ID. /// /// The user ID. /// The document ID. /// An error message or null if successful. public string Delete(long deletedByID, long documentID) { var document = GetDocument(documentID); if(document == null) { return "Document does not exist"; } document.IsCancelled = true; document.UpdatedByID = deletedByID; document.UpdatedDate = DateTime.Now; Update(document); Save(); return null; } #endregion #region GetDocuments /// /// Gets the documents. /// /// The entity ID. /// The item ID. /// public IEnumerable GetDocuments(int entityID, long itemID) { return from q in Context.Documents.Include("UserCreatedBy").Include("UserUpdatedBy").Include("DocumentMimeType") where q.EntityID == entityID && (itemID != -1 ? q.ItemID == itemID : true) && !q.IsCancelled select q; } #endregion #region CopyDocuments /// /// Copies the documents. /// /// The user ID. /// The source document I ds. /// The target entity ID. /// The target item ID. /// public KeyValuePair CopyDocuments(long userID, string sourceDocumentIDs, int targetEntityID, long targetItemID) { KeyValuePair returnResult; try { var result = Context.Pr_DocumentCopyMany(sourceDocumentIDs, targetItemID, targetEntityID, userID).First(); returnResult = result != "1" ? new KeyValuePair(1, "Error: " + result) : new KeyValuePair(1, "Success"); } catch(Exception ex) { returnResult = new KeyValuePair(0, ex.InnerException.Message); } return returnResult; } #endregion #region GetDocumentObject /// /// Gets the document object. /// /// The document ID. /// public FileObject GetDocumentObject(long documentID) { var doc = Context.Documents.Where(d => d.DocumentID == documentID).Include("DocumentStoreLocation").Include("DocumentMimeType").FirstOrDefault(); return doc == null ? null : Download(doc); } #endregion #region GetDocumentObjectWithoutBlob /// /// Gets the document object. /// /// The document ID. /// public Document GetDocumentObjectWithoutBlob(long documentID) { var doc = Context.Documents.Where(d => d.DocumentID == documentID).Include("DocumentType").Include("DocumentMimeType").FirstOrDefault(); return doc; } #endregion #region GetDocumentType /// /// Gets the document type object. /// /// The document type ID. /// public DocumentType GetDocumentType(long documentTypeID) { return Context.DocumentTypes.Where(d => d.DocumentTypeID == documentTypeID).FirstOrDefault(); } #endregion #region GetDocumentTemplateData /// /// Gets the document template data. /// /// The entity ID. /// The item ID. /// public XElement GetDocumentTemplateData(int entityID, long itemID) { return XElement.Parse(Context.Pr_DocumentTemplateDataGet(entityID, itemID).FirstOrDefault()); } #endregion #region GetDocumentStoreLocation DocumentStoreLocation GetDocumentStoreLocation(long documentStoreLocationID) { return Context.DocumentStoreLocations.Where(l => l.DocumentStoreLocationID == documentStoreLocationID).FirstOrDefault(); } #endregion #region GetMimeType /// /// Gets the of the ; /// returns the if not found. /// /// Type of the file MIME. /// /// The of the or the if not found. /// DocumentMimeType GetDocumentMimeType(string fileMimeType) { DocumentMimeType result = null; var mimeTypes = Context.DocumentMimeTypes.Where(m => m.MimeType == fileMimeType || m.MimeType == DefaultMimeType); foreach(var mimeType in mimeTypes) { if(mimeType.MimeType == fileMimeType) { result = mimeType; break; } result = mimeType; } return result; } #endregion #region Upload /// /// Uploads the specified document. /// /// The document. /// Name of the uploaded by user. /// The content. void Upload(Document doc, string uploadedByUserName, byte[] content) { var fileName = doc.Description; var extension = Path.GetExtension(fileName); var mimeType = doc.DocumentMimeType.MimeType; var location = doc.DocumentStoreLocation; try { switch((DocumentStoreTypeEnum)location.DocumentStoreTypeID) { case DocumentStoreTypeEnum.SQL: using(var conn = new SqlConnection(location.ConnectionString)) { conn.Open(); var cmd = new SqlCommand("Doc.Pr_DocumentStoreCreate", conn) { CommandType = CommandType.StoredProcedure }; cmd.Parameters.Add(new SqlParameter("@DocumentID", doc.DocumentID)); cmd.Parameters.Add(new SqlParameter("@ContentBLOB", content)); cmd.Parameters.Add(new SqlParameter("@MimeType", mimeType)); cmd.Parameters.Add(new SqlParameter("@Size", content.Length)); cmd.Parameters.Add(new SqlParameter("@Name", fileName)); cmd.Parameters.Add(new SqlParameter("@Ext", extension)); cmd.ExecuteNonQuery(); } break; } } catch(Exception ex) { Delete(doc.CreatedByID, doc.DocumentID); throw ex; } } #endregion #region Download // doc must include DocumentStoreLocation & DocumentMimeType FileObject Download(Document doc) { var result = new FileObject { ID = doc.DocumentID, Name = doc.Description, Extension = Path.GetExtension(doc.Description), MimeType = doc.DocumentMimeType.MimeType, Content = new byte[0], Length = 0 }; var location = doc.DocumentStoreLocation; switch((DocumentStoreTypeEnum)location.DocumentStoreTypeID) { case DocumentStoreTypeEnum.SQL: using(var conn = new SqlConnection(location.ConnectionString)) { conn.Open(); var cmd = new SqlCommand("Doc.Pr_DocumentStoreGet", conn) { CommandType = CommandType.StoredProcedure }; cmd.Parameters.Add(new SqlParameter("@DocumentID", doc.DocumentID)); using(var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)) { if(reader.Read()) { result.Content = (byte[])reader["ContentBLOB"]; } } } break; } result.Length = result.Content.Length; return result; } #endregion ////#region GetFolderName ////string GetFolderName(long entityID, long itemID) ////{ //// var entity = GetDocumentEntity(entityID); //// return GetFolderName(entity, itemID); ////} ////static string GetFolderName(DocumentEntity entity, long itemID) ////{ //// var idStr = itemID.ToString(); //// if(itemID > 0) //// { //// idStr = idStr.PadLeft(ItemNumberWidth, '0'); //// } //// return entity.FolderPrefix + idStr; ////} ////#endregion #region GetSysSetting /// /// Gets the system setting. /// /// Name of the setting. /// public string GetSysSetting(string settingName) { return Context.Database.SqlQuery("SELECT System.Fn_GetSettingValue(@SettingName)", new SqlParameter("@SettingName", settingName)).FirstOrDefault(); } #endregion #region UpdateDocumentTitle /// /// Updates a document title /// /// public void UpdateDocumentTitle(long documentId, string documentTitle, long updatedById) { Context.Database.ExecuteSqlCommand("UPDATE Doc.Documents SET Title=@p1, UpdatedByID=@p2, UpdatedDate=GETDATE() WHERE DocumentID=@p0", documentId, documentTitle, updatedById); } #endregion #region GetUserNameById /// /// Gets a UserName Derived from the supplied User ID /// /// /// public String GetUserNameByUserID(int userID) { var userObject = Context.DocumentsUsers.FirstOrDefault(a => a.UserID == userID); return userObject == null ? "" : userObject.FullName; } #endregion #region GetEntityDocuments /// /// Gets a list of all documents uplaoded against an entity /// /// public List GetEntityDocuments(int entityID, long itemID) { return Context.Pr_DocumentsGet(entityID, itemID).ToList(); } #endregion #region UpdateDocumentIDOnEntity /// /// Updated the document id on the related entity /// /// public void UpdateDocumentIDOnEntity(long documentID, int entityID, long itemID, string relatedFieldKey, long userID) { Context.Pr_DocumentIDUpdateEntity(documentID, entityID, itemID, relatedFieldKey, userID); } #endregion } }