The Attachment modules provides:
Document imaging with file storage on a SAN, in the cloud (Amazon), or any other file store wrapped with the IFileObject interface
Mail merge capability via the IGenerate interface
Web controls supporting multiple-document uploads, drag-and-drop HTML5 and image previewing
Zip capability
Remote printing
Monitoring and processing of remote locations
Future enhancements planned include:
Bar code generation and scanning
Inbound faxing (with bar code scanning)
Integration with document delivery services (both physical and electronic) via IDelivery interface
Behaviors:
Single attachment upload control
Multiple attachment upload control
Photo control (with lazy loader capabilities)
Document Imaging: IFileObject Interface
The Attachment module's main task is managing files associated with a QBO application. Over the course of time, files uploaded to a QBO site have been stored on:
A web server (but that was insufficient for load balancing situations and backups),
A SAN (but we eventually ran out of SAN space for clients storing hundreds of large images per property inspection),
On Amazon's S3 (where most of our client documents currently reside),
On a data server (to allow SQL direct manipulation of data files for import),
On a client FTP site,
In a client imaging system, and
On the public internet
The various use cases above led to the development of the IFileObject interface. When a user attempts to upload or download a file from a QBO system, the Attachment module loads a plug-in that implements the IFileObject interface, and is coded to read or write streams of data to some underlying repository. Current IFileObject plugins include:
LocalFile (qbo.Attachment.FileObjects.LocalFile): reads and writes from a Windows file system using local paths
UNCFile (qbo.Attachment.FileObjects.UNCFile): reads and writes from a Windows file system using UNC paths (including credentials to access other servers)
S3FileObject (qbo.Attachment.Amazon.S3FileObject): reads and writes from Amazon's Simple Storage Service (S3)
Internet (qbo.Attachment.FileObjects.Internet): reads (but does not write) from the public internet
DistributedFile (qbo.Attachment.FileObjects.DistributedFile): writes to multiple locations
WebDAV (currently a QBO 2.0 plugin only): reads and writes from any WebDAV compliant imaging system
FTP (currently a QBO 2.0 plugin only): reads and writes from any FTP or FTPS site
sFTP (currently a QBO 2.0 plugin only): reads and writes from any sFTP site
The IFileObject includes the following methods:
Read(streamToWriteTo, relativePath): reads a file into a stream
Write(streamToReadFrom, relativePath): writes a stream to a file
List(relativePath, pattern, depth): lists files that exist in a file store
Delete(relativePath): deletes a file
Rename(oldPath, newPath): renames a file
Each QBO system will include a configuration file (Config/FileObject.config) that defines the plugins used for the system. Note that a given plugin may be used more than once.
<FileObject>
<FileObjects>
<FileObject Name="LocalFile" Type="qbo.Attachment.FileObjects.LocalFile, qbo.Attachment" Uri="C:\inetpub\local.quandis.net\Upload\LocalFileObject" Compression="false"/>
<FileObject Name="Template" Type="qbo.Attachment.FileObjects.LocalFile, qbo.Attachment" Uri="C:\inetpub\local.quandis.net" Compression="false"/>
<FileObject Name="Database" Type="qbo.Attachment.FileObjects.UNCFile, qbo.Attachment" Uri="//192.168.168.17/UATFilestore/uatval.quandis.net/" Compression="false"/>
<FileObject Name="AmazonS3" Type="qbo.Attachment.Amazon.S3FileObject, qbo.Attachment.Amazon" Uri="https://localhost-quandis-net.s3.amazonaws.com">
<Permissions>
<Permission Method="ListFiles" Role="Administrators"/>
</Permissions>
</FileObject>
<FileObject Name="ClientABucket" Type="qbo.Attachment.Amazon.S3FileObject, qbo.Attachment.Amazon" Uri="https://clientA-quandis-net.s3.amazonaws.com">
<Permissions>
<Permission Method="ListFiles" Function="ClientAListFiles"/>
</Permissions>
</FileObject>
<FileObject Name="Internet" Type="qbo.Attachment.FileObjects.Internet, qbo.Attachment" Uri="" Compression="false"/>
</FileObjects>
</FileObject>
These low-level methods can be accessed from Attachment/FileObject.ashx directly. For example:
FileObject.ashx/ReadFile?FileObject=AmazonS3&Path=/Loan/12345/MyLoanDoc.pdf
FileObject.ashx/ListFiles?FileObject=AmazonS3&Path=/Loan/12345/&Pattern=*&Depth=0
FileObject.ashx/DeleteFile?FileObject=AmazonS3&Path=/Loan/12345/MyLoanDoc.pdf
Normally, however, files are manipulated at the same time Attachment rows are manipulated. For example:
When uploading a file, create an Attachment row, and stream the file to the appropriate location
When downloading a file, ensure the user has access to the corresponding Attachment row
When deleting an attachment, delete the underlying file as well
Attachment.ashx methods include:
Upload: used for HTML and Flash file uploads
UploadChunk: used for HTML5 uploads
View?ID=1988: used to view the document for AttachmentID 1988
Download?ID=1988: used to download the document for AttachmentID 1988
Write?ID=1988:
writes the HttpContext.Request.InputStream to the file underlying AttachmentID 1988
Write?Object=Loan&ObjectID=12345:
writes the InputStream to a new file, and creates a new Attachment under Loan 12345
CopyFile?ID=1988&&ID=1989&FileObject=ClientABucket&PathURL=/{Object}/{ObjectID}/{Guid}.{Uri.Extension}:
copies a file to ClientABucket, using a path like /Loan/12345/e326f796-56d2-422b-b6f6-c568fbfb7fa2.pdf
the original file and Attachment record remain unchanged
TransferFile?ID=1988&&ID=1989&FileObject=AmazonS3&PathURL=/{Uri.Host}/{Year}-{Month}/{Uri.FileName}:
copies the files underlying AttachmetnIDs 1988 and 1989 to AmazonS3
changes the PathURL to something like /images.sears.com/2012-05/MyOriginalFileName.jpg
modifies the Attachments to point to them
leaves the original files alone
MoveFile?ID=1988&&ID=1989&FileObject=AmazonS3:
moves the files underlying AttachmetnIDs 1988 and 1989 from their current location to AmazonS3
leaves the PathURL alone
modifies the Attachments to point to them
deletes the original
Notes:
See AttachmentObject.GetRelativePath() to see the string substitution you can use in PathURL