github.com/jancarloviray/community@v0.41.1-0.20170124221257-33a66c87cf2f/core/api/endpoint/conversion_endpoint.go (about)

     1  // Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
     2  //
     3  // This software (Documize Community Edition) is licensed under
     4  // GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
     5  //
     6  // You can operate outside the AGPL restrictions by purchasing
     7  // Documize Enterprise Edition and obtaining a commercial license
     8  // by contacting <sales@documize.com>.
     9  //
    10  // https://documize.com
    11  
    12  package endpoint
    13  
    14  import (
    15  	"bytes"
    16  	"encoding/json"
    17  	"errors"
    18  	"fmt"
    19  	"io"
    20  	"net/http"
    21  	"strings"
    22  
    23  	"github.com/documize/community/core/api/endpoint/models"
    24  	"github.com/documize/community/core/api/entity"
    25  	"github.com/documize/community/core/api/request"
    26  	"github.com/documize/community/core/api/store"
    27  	"github.com/documize/community/core/api/util"
    28  	api "github.com/documize/community/core/convapi"
    29  	"github.com/documize/community/core/log"
    30  
    31  	uuid "github.com/nu7hatch/gouuid"
    32  
    33  	"github.com/gorilla/mux"
    34  )
    35  
    36  func uploadDocument(w http.ResponseWriter, r *http.Request) (string, string, string) {
    37  	method := "uploadDocument"
    38  	p := request.GetPersister(r)
    39  
    40  	params := mux.Vars(r)
    41  	folderID := params["folderID"]
    42  
    43  	if !p.CanUploadDocument(folderID) {
    44  		writeForbiddenError(w)
    45  		return "", "", ""
    46  	}
    47  
    48  	// grab file
    49  	filedata, filename, err := r.FormFile("attachment")
    50  
    51  	if err != nil {
    52  		writeMissingDataError(w, method, "attachment")
    53  		return "", "", ""
    54  	}
    55  
    56  	b := new(bytes.Buffer)
    57  	_, err = io.Copy(b, filedata)
    58  
    59  	if err != nil {
    60  		writeServerError(w, method, err)
    61  		return "", "", ""
    62  	}
    63  
    64  	// generate job id
    65  	var job = "some-uuid"
    66  
    67  	newUUID, err := uuid.NewV4()
    68  
    69  	if err != nil {
    70  		writeServerError(w, method, err)
    71  		return "", "", ""
    72  	}
    73  
    74  	job = newUUID.String()
    75  
    76  	err = storageProvider.Upload(job, filename.Filename, b.Bytes())
    77  
    78  	if err != nil {
    79  		writeServerError(w, method, err)
    80  		return "", "", ""
    81  	}
    82  
    83  	log.Info(fmt.Sprintf("Org %s (%s) [Uploaded] %s", p.Context.OrgName, p.Context.OrgID, filename.Filename))
    84  
    85  	return job, folderID, p.Context.OrgID
    86  }
    87  
    88  func convertDocument(w http.ResponseWriter, r *http.Request, job, folderID string, conversion api.ConversionJobRequest) {
    89  	method := "convertDocument"
    90  	p := request.GetPersister(r)
    91  
    92  	var fileResult *api.DocumentConversionResponse
    93  	var filename string
    94  	var err error
    95  
    96  	filename, fileResult, err = storageProvider.Convert(conversion)
    97  
    98  	if err != nil {
    99  		writePayloadError(w, method, err)
   100  		return
   101  	}
   102  
   103  	if fileResult.Err != "" {
   104  		writeGeneralSQLError(w, method, errors.New(fileResult.Err))
   105  		return
   106  	}
   107  
   108  	// NOTE: empty .docx documents trigger this error
   109  	if len(fileResult.Pages) == 0 {
   110  		writeMissingDataError(w, method, "no pages in document")
   111  		return
   112  	}
   113  
   114  	// All the commented-out code below should be in following function call
   115  
   116  	newDocument, err := processDocument(p, filename, job, folderID, fileResult)
   117  
   118  	if err != nil {
   119  		writeServerError(w, method, err)
   120  		return
   121  	}
   122  
   123  	json, err := json.Marshal(newDocument)
   124  
   125  	if err != nil {
   126  		writeJSONMarshalError(w, method, "conversion", err)
   127  		return
   128  	}
   129  
   130  	writeSuccessBytes(w, json)
   131  }
   132  
   133  // UploadConvertDocument is an endpoint to both upload and convert a document
   134  func UploadConvertDocument(w http.ResponseWriter, r *http.Request) {
   135  	job, folderID, orgID := uploadDocument(w, r)
   136  	if job == "" {
   137  		return // error already handled
   138  	}
   139  	convertDocument(w, r, job, folderID, api.ConversionJobRequest{
   140  		Job:        job,
   141  		IndexDepth: 4,
   142  		OrgID:      orgID,
   143  	})
   144  }
   145  
   146  func processDocument(p request.Persister, filename, job, folderID string, fileResult *api.DocumentConversionResponse) (newDocument entity.Document, err error) {
   147  	// Convert into database objects
   148  	document := store.ConvertFileResult(filename, fileResult)
   149  	document.Job = job
   150  	document.OrgID = p.Context.OrgID
   151  	document.LabelID = folderID
   152  	document.UserID = p.Context.UserID
   153  	documentID := util.UniqueID()
   154  	document.RefID = documentID
   155  
   156  	tx, err := request.Db.Beginx()
   157  
   158  	log.IfErr(err)
   159  
   160  	p.Context.Transaction = tx
   161  
   162  	err = p.AddDocument(document)
   163  
   164  	if err != nil {
   165  		log.IfErr(tx.Rollback())
   166  		log.Error("Cannot insert new document", err)
   167  		return
   168  	}
   169  
   170  	//err = processPage(documentID, fileResult.PageFiles, fileResult.Pages.Children[0], 1, p)
   171  
   172  	for k, v := range fileResult.Pages {
   173  		var page entity.Page
   174  		page.OrgID = p.Context.OrgID
   175  		page.DocumentID = documentID
   176  		page.Level = v.Level
   177  		page.Title = v.Title
   178  		page.Body = string(v.Body)
   179  		page.Sequence = float64(k+1) * 1024.0 // need to start above 0 to allow insertion before the first item
   180  		pageID := util.UniqueID()
   181  		page.RefID = pageID
   182  		page.ContentType = "wysiwyg"
   183  		page.PageType = "section"
   184  
   185  		meta := entity.PageMeta{}
   186  		meta.PageID = pageID
   187  		meta.RawBody = page.Body
   188  		meta.Config = "{}"
   189  
   190  		model := models.PageModel{}
   191  		model.Page = page
   192  		model.Meta = meta
   193  
   194  		err = p.AddPage(model)
   195  
   196  		if err != nil {
   197  			log.IfErr(tx.Rollback())
   198  			log.Error("Cannot process page newly added document", err)
   199  			return
   200  		}
   201  	}
   202  
   203  	for _, e := range fileResult.EmbeddedFiles {
   204  		//fmt.Println("DEBUG embedded file info", document.OrgId, document.Job, e.Name, len(e.Data), e.ID)
   205  		var a entity.Attachment
   206  		a.DocumentID = documentID
   207  		a.Job = document.Job
   208  		a.FileID = e.ID
   209  		a.Filename = strings.Replace(e.Name, "embeddings/", "", 1)
   210  		a.Data = e.Data
   211  		refID := util.UniqueID()
   212  		a.RefID = refID
   213  
   214  		err = p.AddAttachment(a)
   215  
   216  		if err != nil {
   217  			log.IfErr(tx.Rollback())
   218  			log.Error("Cannot add attachment for newly added document", err)
   219  			return
   220  		}
   221  	}
   222  
   223  	log.IfErr(tx.Commit())
   224  
   225  	newDocument, err = p.GetDocument(documentID)
   226  
   227  	if err != nil {
   228  		log.Error("Cannot fetch newly added document", err)
   229  		return
   230  	}
   231  
   232  	// New code from normal conversion code
   233  
   234  	tx, err = request.Db.Beginx()
   235  
   236  	if err != nil {
   237  		log.Error("Cannot begin a transatcion", err)
   238  		return
   239  	}
   240  
   241  	p.Context.Transaction = tx
   242  
   243  	err = p.UpdateDocument(newDocument) // TODO review - this seems to write-back an unaltered record from that read above, but within that it calls searches.UpdateDocument() to reindex the doc.
   244  
   245  	if err != nil {
   246  		log.IfErr(tx.Rollback())
   247  		log.Error("Cannot update an imported document", err)
   248  		return
   249  	}
   250  
   251  	log.IfErr(tx.Commit())
   252  
   253  	// End new code
   254  
   255  	return
   256  }