Example #1
0
        /// <summary>
        /// CreateDocument returns an error result when an error occurs; null otherwise. If CreateDocument
        /// return null, then the out parameter doc is guaranteed to be valid.
        /// </summary>
        /// <returns>An error result or null. A null result indicates that the document was created successfully.</returns>
        IHttpActionResult CreateDocument(List <Error> errors, Application app, DocumentCreateAttributes attr, out Document doc)
        {
            doc = null;

            var docType = app.Core.DocumentTypes.Find(attr.DocumentType);

            if (docType == null)
            {
                errors.Add(BadRequestError($"The DocumentType '{attr.DocumentType}' could not be found."));
            }

            var fileType = app.Core.FileTypes.Find(attr.FileType);

            if (fileType == null)
            {
                errors.Add(BadRequestError($"The FileType '{attr.FileType}' could not be found."));
            }

            var pageData = app.Core.Storage.CreatePageData(attr.Stream, attr.FileExtension);

            if (pageData == null)
            {
                errors.Add(BadRequestError($"Unable to create page data for '{attr.FileExtension}'."));
            }

            var props = app.Core.Storage.CreateStoreNewDocumentProperties(docType, fileType);

            if (props == null)
            {
                return(BadRequestResult($"Unable to create document properties for '{attr.DocumentType}' and '{attr.FileType}'."));
            }

            if (errors.Any())
            {
                return(BadRequestResult(errors));
            }

            props.AddKeyword(Global.Config.DocIndexKeyName, attr.IndexKey);
            props.DocumentDate  = DateTime.Now;
            props.Comment       = attr.Comment;
            props.ExpandKeysets = false;

            if (attr.Keywords != null)
            {
                foreach (var kw in attr.Keywords)
                {
                    props.AddKeyword(kw.Name, kw.Value);
                }
            }

            doc = app.Core.Storage.StoreNewDocument(pageData, props);
            if (doc == null)
            {
                return(BadRequestResult("Unable to create document."));
            }

            return(null);
        }
Example #2
0
        public async Task <IHttpActionResult> Post()
        {
            // We only support multi-part post content.
            if (!Request.Content.IsMimeMultipartContent())
            {
                return(BadRequestResult("Uploading a document requires a multi-part POST request."));
            }

            Stream docStream               = null;
            string docExtension            = null;
            DocumentPostAttributes docAttr = null;

            // We bundle the bad requests in one response.
            var errors = new List <Error>();

            try
            {
                var provider = await Request.Content.ReadAsMultipartAsync(
                    new MultipartMemoryStreamProvider());

                foreach (HttpContent content in provider.Contents)
                {
                    // The Content-Disposition header is required.
                    if (content.Headers.ContentDisposition == null)
                    {
                        return(BadRequestResult("A Content-Disposition header is required."));
                    }

                    var dispoName = content.Headers.ContentDisposition.Name.Trim('"');

                    if (dispoName == "file")
                    {
                        // The content is a file.
                        // Only allow one content file.
                        if ((docStream != null) || !string.IsNullOrWhiteSpace(docExtension))
                        {
                            return(BadRequestResult("More than one document content was included."));
                        }

                        var fileName = content.Headers.ContentDisposition.FileName.Trim('"');
                        docStream    = content.ReadAsStreamAsync().Result;
                        docExtension = Path.GetExtension(fileName).TrimStart('.');

                        // Handle base64 file encoding.
                        if (content.Headers.ContentEncoding.Any(x => x == "base64") ||
                            content.Headers.Any(x => x.Key == "Content-Transfer-Encoding" && x.Value.Any(v => v == "base64")))
                        {
                            /*
                             * We need to read the file content, bease64 decode it and set
                             * docStream to be the decoded content.
                             */
                            using (var reader = new StreamReader(docStream))
                            {
                                var str = reader.ReadToEnd();
                                docStream = new MemoryStream(Convert.FromBase64String(str));
                            }
                        }
                    }
                    else if (dispoName == "attributes")
                    {
                        // The content is JSON.
                        // Only allow one JSON attributes.
                        if (docAttr != null)
                        {
                            return(BadRequestResult("More than one document attributes was included."));
                        }

                        docAttr = JObject
                                  .Parse(content.ReadAsStringAsync().Result)
                                  .ToObject <DocumentPostAttributes>();
                    }
                    else
                    {
                        return(BadRequestResult($"Unexpected Content-Disposition header of name '{dispoName}'."));
                    }
                }
            }
            catch (JsonReaderException ex)
            {
                errors.Add(BadRequestError($"JSON parse error. {ex.Message}"));
            }
            catch (IOException ex) when(ex.Message.Contains("MIME multipart message is not complete"))
            {
                errors.Add(BadRequestError(ex.Message));
            }
            catch (Exception ex)
            {
                return(InternalErrorResult(ex.Message));
            }

            if ((docStream == null) || string.IsNullOrWhiteSpace(docExtension))
            {
                errors.Add(BadRequestError("The required parameter 'file' is missing."));
            }
            if (docAttr == null)
            {
                errors.Add(BadRequestError("The required parameter 'attributes' is missing."));
            }
            if ((docAttr == null) || string.IsNullOrWhiteSpace(docAttr.IndexKey))
            {
                errors.Add(BadRequestError("The required parameter 'IndexKey' is empty."));
            }
            if ((docAttr == null) || string.IsNullOrWhiteSpace(docAttr.DocumentType))
            {
                errors.Add(BadRequestError("The required parameter 'DocumentType' is empty."));
            }

            // Check if there are any errors. If there are then return them.
            if (errors.Any())
            {
                return(BadRequestResult(errors));
            }

            return(TryHandleRequest(app =>
            {
                // Validate that the doc type is actually valid.
                var docType = app.Core.DocumentTypes.Find(docAttr.DocumentType);
                if (docType == null)
                {
                    errors.Add(BadRequestError($"The DocumentType '{docAttr.DocumentType}' could not be found."));
                }

                var createAttr = new DocumentCreateAttributes
                {
                    DocumentType = Global.Config.StagingDocType,
                    Comment = docAttr.Comment,
                    IndexKey = docAttr.IndexKey,
                    Keywords = docAttr.Keywords,
                    FileType = docAttr.FileType ?? docExtension,
                    FileExtension = docExtension,
                    Stream = docStream,
                };
                var error = CreateDocument(errors, app, createAttr, out var doc);
                if (error != null)
                {
                    return error;
                }

                // We must get the document ID from this thread and not the task thread since
                // the document could go out of scope before the task starts.
                var docId = doc.ID;
                Task.Run(() =>
                {
                    MoveDocumentToWorkflow(docId, docType);
                });

                return DocumentResult(doc, docId.ToString(), docAttr.DocumentType);
            }));
        }