github.com/jancarloviray/community@v0.41.1-0.20170124221257-33a66c87cf2f/core/api/endpoint/templates_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  	"encoding/json"
    16  	"errors"
    17  	"fmt"
    18  	"io/ioutil"
    19  	"net/http"
    20  
    21  	"database/sql"
    22  
    23  	"github.com/gorilla/mux"
    24  
    25  	"github.com/documize/community/core/api/convert"
    26  	"github.com/documize/community/core/api/endpoint/models"
    27  	"github.com/documize/community/core/api/entity"
    28  	"github.com/documize/community/core/api/request"
    29  	"github.com/documize/community/core/api/util"
    30  	api "github.com/documize/community/core/convapi"
    31  	"github.com/documize/community/core/log"
    32  	"github.com/documize/community/core/utility"
    33  
    34  	uuid "github.com/nu7hatch/gouuid"
    35  )
    36  
    37  // SaveAsTemplate saves existing document as a template.
    38  func SaveAsTemplate(w http.ResponseWriter, r *http.Request) {
    39  	method := "SaveAsTemplate"
    40  	p := request.GetPersister(r)
    41  
    42  	var model struct {
    43  		DocumentID string
    44  		Name       string
    45  		Excerpt    string
    46  	}
    47  
    48  	defer utility.Close(r.Body)
    49  	body, err := ioutil.ReadAll(r.Body)
    50  
    51  	if err != nil {
    52  		writeBadRequestError(w, method, "Bad payload")
    53  		return
    54  	}
    55  
    56  	err = json.Unmarshal(body, &model)
    57  
    58  	if err != nil {
    59  		writePayloadError(w, method, err)
    60  		return
    61  	}
    62  
    63  	if !p.CanChangeDocument(model.DocumentID) {
    64  		writeForbiddenError(w)
    65  		return
    66  	}
    67  
    68  	// DB transaction
    69  	tx, err := request.Db.Beginx()
    70  
    71  	if err != nil {
    72  		writeTransactionError(w, method, err)
    73  		return
    74  	}
    75  
    76  	p.Context.Transaction = tx
    77  
    78  	// Duplicate document
    79  	doc, err := p.GetDocument(model.DocumentID)
    80  
    81  	if err != nil {
    82  		writeServerError(w, method, err)
    83  		return
    84  	}
    85  
    86  	docID := util.UniqueID()
    87  	doc.Template = true
    88  	doc.Title = model.Name
    89  	doc.Excerpt = model.Excerpt
    90  	doc.RefID = docID
    91  	doc.ID = 0
    92  	doc.Template = true
    93  
    94  	// Duplicate pages and associated meta
    95  	pages, err := p.GetPages(model.DocumentID)
    96  	var pageModel []models.PageModel
    97  
    98  	if err != nil {
    99  		writeServerError(w, method, err)
   100  		return
   101  	}
   102  
   103  	for _, page := range pages {
   104  		page.DocumentID = docID
   105  		page.ID = 0
   106  
   107  		meta, err2 := p.GetPageMeta(page.RefID)
   108  
   109  		if err2 != nil {
   110  			writeServerError(w, method, err2)
   111  			return
   112  		}
   113  
   114  		pageID := util.UniqueID()
   115  		page.RefID = pageID
   116  
   117  		meta.PageID = pageID
   118  		meta.DocumentID = docID
   119  
   120  		m := models.PageModel{}
   121  
   122  		m.Page = page
   123  		m.Meta = meta
   124  
   125  		pageModel = append(pageModel, m)
   126  	}
   127  
   128  	// Duplicate attachments
   129  	attachments, err := p.GetAttachments(model.DocumentID)
   130  
   131  	for i, a := range attachments {
   132  		a.DocumentID = docID
   133  		a.RefID = util.UniqueID()
   134  		a.ID = 0
   135  		attachments[i] = a
   136  	}
   137  
   138  	// Now create the template: document, attachments, pages and their meta
   139  	err = p.AddDocument(doc)
   140  
   141  	if err != nil {
   142  		log.IfErr(tx.Rollback())
   143  		writeGeneralSQLError(w, method, err)
   144  		return
   145  	}
   146  
   147  	for _, a := range attachments {
   148  		err = p.AddAttachment(a)
   149  
   150  		if err != nil {
   151  			log.IfErr(tx.Rollback())
   152  			writeGeneralSQLError(w, method, err)
   153  			return
   154  		}
   155  	}
   156  
   157  	for _, m := range pageModel {
   158  		err = p.AddPage(m)
   159  
   160  		if err != nil {
   161  			log.IfErr(tx.Rollback())
   162  			writeGeneralSQLError(w, method, err)
   163  			return
   164  		}
   165  	}
   166  
   167  	// Commit and return new document template
   168  	log.IfErr(tx.Commit())
   169  
   170  	doc, err = p.GetDocument(docID)
   171  
   172  	if err != nil {
   173  		writeGeneralSQLError(w, method, err)
   174  		return
   175  	}
   176  
   177  	d, err := json.Marshal(doc)
   178  
   179  	if err != nil {
   180  		writeJSONMarshalError(w, method, "document", err)
   181  		return
   182  	}
   183  
   184  	writeSuccessBytes(w, d)
   185  }
   186  
   187  // GetSavedTemplates returns all templates saved by the user
   188  func GetSavedTemplates(w http.ResponseWriter, r *http.Request) {
   189  	method := "GetSavedTemplates"
   190  	p := request.GetPersister(r)
   191  
   192  	documents, err := p.GetDocumentTemplates()
   193  
   194  	if err != nil {
   195  		writeGeneralSQLError(w, method, err)
   196  		return
   197  	}
   198  
   199  	templates := []entity.Template{}
   200  
   201  	for _, d := range documents {
   202  
   203  		var template = entity.Template{}
   204  
   205  		template.ID = d.RefID
   206  		template.Title = d.Title
   207  		template.Description = d.Excerpt
   208  		template.Author = ""
   209  		template.Dated = d.Created
   210  		template.Type = entity.TemplateTypePrivate
   211  
   212  		templates = append(templates, template)
   213  	}
   214  
   215  	data, err := json.Marshal(templates)
   216  
   217  	if err != nil {
   218  		writeJSONMarshalError(w, method, "template", err)
   219  		return
   220  	}
   221  
   222  	writeSuccessBytes(w, data)
   223  }
   224  
   225  // GetStockTemplates returns available templates from the public Documize repository.
   226  func GetStockTemplates(w http.ResponseWriter, r *http.Request) {
   227  	method := "GetStockTemplates"
   228  
   229  	var templates = fetchStockTemplates()
   230  
   231  	json, err := json.Marshal(templates)
   232  
   233  	if err != nil {
   234  		writeJSONMarshalError(w, method, "template", err)
   235  		return
   236  	}
   237  
   238  	writeSuccessBytes(w, json)
   239  }
   240  
   241  // StartDocumentFromStockTemplate creates new document using one of the stock templates
   242  func StartDocumentFromStockTemplate(w http.ResponseWriter, r *http.Request) {
   243  	method := "StartDocumentFromStockTemplate"
   244  	p := request.GetPersister(r)
   245  
   246  	if !p.Context.Editor {
   247  		writeForbiddenError(w)
   248  		return
   249  	}
   250  
   251  	params := mux.Vars(r)
   252  	folderID := params["folderID"]
   253  
   254  	if len(folderID) == 0 {
   255  		writeMissingDataError(w, method, "folderID")
   256  		return
   257  	}
   258  
   259  	templateID := params["templateID"]
   260  
   261  	if len(templateID) == 0 {
   262  		writeMissingDataError(w, method, "templateID")
   263  		return
   264  	}
   265  
   266  	filename, template, err := fetchStockTemplate(templateID)
   267  
   268  	if err != nil {
   269  		writeServerError(w, method, err)
   270  		return
   271  	}
   272  
   273  	if len(template) == 0 {
   274  		writeBadRequestError(w, method, "No data found in template")
   275  	}
   276  
   277  	fileRequest := api.DocumentConversionRequest{}
   278  	fileRequest.Filedata = template
   279  	fileRequest.Filename = fmt.Sprintf("%s.docx", filename)
   280  	fileRequest.PageBreakLevel = 4
   281  	//fileRequest.Job = templateID
   282  	//fileRequest.OrgID = p.Context.OrgID
   283  
   284  	//	fileResult, err := store.RunConversion(fileRequest)
   285  	//fileResultI, err := plugins.Lib.Run(nil, "Convert", "docx", fileRequest)
   286  	fileResult, err := convert.Convert(nil, "docx", &fileRequest)
   287  	if err != nil {
   288  		writeServerError(w, method, err)
   289  		return
   290  	}
   291  
   292  	model, err := processDocument(p, fileRequest.Filename, templateID, folderID, fileResult)
   293  
   294  	if err != nil {
   295  		writeServerError(w, method, err)
   296  		return
   297  	}
   298  
   299  	json, err := json.Marshal(model)
   300  
   301  	if err != nil {
   302  		writeJSONMarshalError(w, method, "stockTemplate", err)
   303  		return
   304  	}
   305  
   306  	writeSuccessBytes(w, json)
   307  }
   308  
   309  // StartDocumentFromSavedTemplate creates new document using a saved document as a template.
   310  // If template ID is ZERO then we provide an Empty Document as the new document.
   311  func StartDocumentFromSavedTemplate(w http.ResponseWriter, r *http.Request) {
   312  	method := "StartDocumentFromSavedTemplate"
   313  	p := request.GetPersister(r)
   314  
   315  	params := mux.Vars(r)
   316  	folderID := params["folderID"]
   317  
   318  	if len(folderID) == 0 {
   319  		writeMissingDataError(w, method, "folderID")
   320  		return
   321  	}
   322  
   323  	templateID := params["templateID"]
   324  
   325  	// We are OK with zero valued template ID because it signals 'give me empty document'
   326  	if len(templateID) == 0 {
   327  		writeMissingDataError(w, method, "templateID")
   328  		return
   329  	}
   330  
   331  	// Define an empty document just in case user wanted one.
   332  	var err error
   333  	var d = entity.Document{}
   334  	d.Title = "New Document"
   335  	d.Location = fmt.Sprintf("template-%s", templateID)
   336  	d.Excerpt = "A new document"
   337  	d.Slug = utility.MakeSlug(d.Title)
   338  	d.Tags = ""
   339  	d.Layout = "doc"
   340  	d.LabelID = folderID
   341  	documentID := util.UniqueID()
   342  	d.RefID = documentID
   343  
   344  	var pages = []entity.Page{}
   345  	var attachments = []entity.Attachment{}
   346  
   347  	// Fetch document and associated pages, attachments if we have template ID
   348  	if templateID != "0" {
   349  		d, err = p.GetDocument(templateID)
   350  
   351  		if err == sql.ErrNoRows {
   352  			api.WriteError(w, errors.New("NotFound"))
   353  			return
   354  		}
   355  
   356  		if err != nil {
   357  			api.WriteError(w, err)
   358  			return
   359  		}
   360  
   361  		pages, err = p.GetPages(templateID)
   362  		attachments, err = p.GetAttachmentsWithData(templateID)
   363  	}
   364  
   365  	// create new document
   366  	tx, err := request.Db.Beginx()
   367  
   368  	if err != nil {
   369  		writeTransactionError(w, method, err)
   370  		return
   371  	}
   372  
   373  	p.Context.Transaction = tx
   374  
   375  	// Prepare new document
   376  	documentID = util.UniqueID()
   377  	d.RefID = documentID
   378  	d.Template = false
   379  	d.LabelID = folderID
   380  	d.UserID = p.Context.UserID
   381  
   382  	err = p.AddDocument(d)
   383  
   384  	if err != nil {
   385  		log.IfErr(tx.Rollback())
   386  		writeGeneralSQLError(w, method, err)
   387  		return
   388  	}
   389  
   390  	for _, page := range pages {
   391  		meta, err2 := p.GetPageMeta(page.RefID)
   392  		if err2 != nil {
   393  			log.IfErr(tx.Rollback())
   394  			writeGeneralSQLError(w, method, err)
   395  			return
   396  		}
   397  
   398  		page.DocumentID = documentID
   399  		pageID := util.UniqueID()
   400  		page.RefID = pageID
   401  
   402  		// meta := entity.PageMeta{}
   403  		meta.PageID = pageID
   404  		meta.DocumentID = documentID
   405  
   406  		// meta.RawBody = page.Body
   407  
   408  		model := models.PageModel{}
   409  		model.Page = page
   410  		model.Meta = meta
   411  
   412  		err = p.AddPage(model)
   413  
   414  		if err != nil {
   415  			log.IfErr(tx.Rollback())
   416  			writeGeneralSQLError(w, method, err)
   417  			return
   418  		}
   419  	}
   420  
   421  	newUUID, err := uuid.NewV4()
   422  
   423  	if err != nil {
   424  		log.IfErr(tx.Rollback())
   425  		writeServerError(w, method, err)
   426  		return
   427  	}
   428  
   429  	for _, a := range attachments {
   430  		a.DocumentID = documentID
   431  		a.Job = newUUID.String()
   432  		random := util.GenerateSalt()
   433  		a.FileID = random[0:9]
   434  		attachmentID := util.UniqueID()
   435  		a.RefID = attachmentID
   436  
   437  		err = p.AddAttachment(a)
   438  
   439  		if err != nil {
   440  			log.IfErr(tx.Rollback())
   441  			writeServerError(w, method, err)
   442  			return
   443  		}
   444  	}
   445  
   446  	log.IfErr(tx.Commit())
   447  
   448  	newDocument, err := p.GetDocument(documentID)
   449  
   450  	if err != nil {
   451  		writeServerError(w, method, err)
   452  		return
   453  	}
   454  
   455  	data, err := json.Marshal(newDocument)
   456  
   457  	if err != nil {
   458  		writeJSONMarshalError(w, method, "document", err)
   459  		return
   460  	}
   461  
   462  	writeSuccessBytes(w, data)
   463  }
   464  
   465  type templateConfig struct {
   466  	ID          string `json:"id"`
   467  	Description string `json:"description"`
   468  	Author      string `json:"author"`
   469  	Title       string `json:"title"`
   470  }
   471  
   472  func fetchStockTemplates() (templates []entity.Template) {
   473  	path := "./templates"
   474  	templates = make([]entity.Template, 0)
   475  
   476  	folders, err := ioutil.ReadDir(path)
   477  	log.IfErr(err)
   478  	for _, folder := range folders {
   479  
   480  		if folder.IsDir() {
   481  			files, err := ioutil.ReadDir(path + "/" + folder.Name())
   482  			log.IfErr(err)
   483  
   484  			for _, file := range files {
   485  				if !file.IsDir() && file.Name() == "template.json" {
   486  					data, err := ioutil.ReadFile(path + "/" + folder.Name() + "/" + file.Name())
   487  
   488  					if err != nil {
   489  						log.Error("error reading template.json", err)
   490  					} else {
   491  						var config = templateConfig{}
   492  						err = json.Unmarshal(data, &config)
   493  
   494  						if err != nil {
   495  							log.Error("error parsing template.json", err)
   496  						} else {
   497  							var template = entity.Template{}
   498  
   499  							template.ID = config.ID
   500  							template.Title = config.Title
   501  							template.Description = config.Description
   502  							template.Author = config.Author
   503  							template.Type = entity.TemplateTypePublic
   504  
   505  							templates = append(templates, template)
   506  						}
   507  					}
   508  				}
   509  			}
   510  		}
   511  	}
   512  
   513  	return
   514  }
   515  
   516  func fetchStockTemplate(ID string) (filename string, template []byte, err error) {
   517  
   518  	path := "./templates"
   519  	folders, err := ioutil.ReadDir(path)
   520  	if err != nil {
   521  		log.Error("error reading template directory", err)
   522  		return "", nil, err
   523  	}
   524  
   525  	for _, folder := range folders {
   526  		if folder.IsDir() {
   527  			files, err := ioutil.ReadDir(path + "/" + folder.Name())
   528  			if err != nil {
   529  				log.Error("error reading template sub-dir", err)
   530  				return "", nil, err
   531  			}
   532  
   533  			for _, file := range files {
   534  				if !file.IsDir() && file.Name() == "template.json" {
   535  					data, err := ioutil.ReadFile(path + "/" + folder.Name() + "/template.json")
   536  
   537  					if err != nil {
   538  						log.Error("error reading template.json", err)
   539  						return "", nil, err
   540  					}
   541  
   542  					var config = templateConfig{}
   543  					err = json.Unmarshal(data, &config)
   544  
   545  					if err != nil {
   546  						log.Error("error parsing template.json", err)
   547  						return "", nil, err
   548  					}
   549  
   550  					if config.ID == ID {
   551  						template, err = ioutil.ReadFile(path + "/" + folder.Name() + "/template.docx")
   552  						return folder.Name(), template, err
   553  					}
   554  				}
   555  			}
   556  		}
   557  	}
   558  
   559  	return
   560  }