github.com/elliott5/community@v0.14.1-0.20160709191136-823126fb026a/documize/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/documize/api/convert" 26 "github.com/documize/community/documize/api/endpoint/models" 27 "github.com/documize/community/documize/api/entity" 28 "github.com/documize/community/documize/api/request" 29 "github.com/documize/community/documize/api/util" 30 "github.com/documize/community/wordsmith/api" 31 "github.com/documize/community/wordsmith/log" 32 "github.com/documize/community/wordsmith/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.LabelID = folderID 340 documentID := util.UniqueID() 341 d.RefID = documentID 342 343 var pages = []entity.Page{} 344 //var pages = make([]entity.Page, 1, 1) 345 //pages[0] = entity.Page{} 346 //pages[0].Title = "Heading" 347 //pages[0].Body = "<p>Some content here.</p>" 348 //pages[0].Level = 1 349 //pages[0].Sequence = 1 350 351 var attachments = []entity.Attachment{} 352 353 // Fetch document and associated pages, attachments if we have template ID 354 if templateID != "0" { 355 d, err = p.GetDocument(templateID) 356 357 if err == sql.ErrNoRows { 358 api.WriteError(w, errors.New("NotFound")) 359 return 360 } 361 362 if err != nil { 363 api.WriteError(w, err) 364 return 365 } 366 367 pages, err = p.GetPages(templateID) 368 attachments, err = p.GetAttachmentsWithData(templateID) 369 } 370 371 // create new document 372 tx, err := request.Db.Beginx() 373 374 if err != nil { 375 writeTransactionError(w, method, err) 376 return 377 } 378 379 p.Context.Transaction = tx 380 381 // Prepare new document 382 documentID = util.UniqueID() 383 d.RefID = documentID 384 d.Template = false 385 d.LabelID = folderID 386 d.UserID = p.Context.UserID 387 388 err = p.AddDocument(d) 389 390 if err != nil { 391 log.IfErr(tx.Rollback()) 392 writeGeneralSQLError(w, method, err) 393 return 394 } 395 396 for _, page := range pages { 397 page.DocumentID = documentID 398 pageID := util.UniqueID() 399 page.RefID = pageID 400 401 meta := entity.PageMeta{} 402 meta.PageID = pageID 403 meta.RawBody = page.Body 404 405 model := models.PageModel{} 406 model.Page = page 407 model.Meta = meta 408 409 err = p.AddPage(model) 410 411 if err != nil { 412 log.IfErr(tx.Rollback()) 413 writeGeneralSQLError(w, method, err) 414 return 415 } 416 } 417 418 newUUID, err := uuid.NewV4() 419 420 if err != nil { 421 log.IfErr(tx.Rollback()) 422 writeServerError(w, method, err) 423 return 424 } 425 426 for _, a := range attachments { 427 a.DocumentID = documentID 428 a.Job = newUUID.String() 429 random := util.GenerateSalt() 430 a.FileID = random[0:9] 431 attachmentID := util.UniqueID() 432 a.RefID = attachmentID 433 434 err = p.AddAttachment(a) 435 436 if err != nil { 437 log.IfErr(tx.Rollback()) 438 writeServerError(w, method, err) 439 return 440 } 441 } 442 443 log.IfErr(tx.Commit()) 444 445 newDocument, err := p.GetDocument(documentID) 446 447 if err != nil { 448 writeServerError(w, method, err) 449 return 450 } 451 452 data, err := json.Marshal(newDocument) 453 454 if err != nil { 455 writeJSONMarshalError(w, method, "document", err) 456 return 457 } 458 459 writeSuccessBytes(w, data) 460 } 461 462 type templateConfig struct { 463 ID string `json:"id"` 464 Description string `json:"description"` 465 Author string `json:"author"` 466 Title string `json:"title"` 467 } 468 469 func fetchStockTemplates() (templates []entity.Template) { 470 path := "./templates" 471 templates = make([]entity.Template, 0) 472 473 folders, err := ioutil.ReadDir(path) 474 log.IfErr(err) 475 for _, folder := range folders { 476 477 if folder.IsDir() { 478 files, err := ioutil.ReadDir(path + "/" + folder.Name()) 479 log.IfErr(err) 480 481 for _, file := range files { 482 if !file.IsDir() && file.Name() == "template.json" { 483 data, err := ioutil.ReadFile(path + "/" + folder.Name() + "/" + file.Name()) 484 485 if err != nil { 486 log.Error("error reading template.json", err) 487 } else { 488 var config = templateConfig{} 489 err = json.Unmarshal(data, &config) 490 491 if err != nil { 492 log.Error("error parsing template.json", err) 493 } else { 494 var template = entity.Template{} 495 496 template.ID = config.ID 497 template.Title = config.Title 498 template.Description = config.Description 499 template.Author = config.Author 500 template.Type = entity.TemplateTypePublic 501 502 templates = append(templates, template) 503 } 504 } 505 } 506 } 507 } 508 } 509 510 return 511 } 512 513 func fetchStockTemplate(ID string) (filename string, template []byte, err error) { 514 515 path := "./templates" 516 folders, err := ioutil.ReadDir(path) 517 if err != nil { 518 log.Error("error reading template directory", err) 519 return "", nil, err 520 } 521 522 for _, folder := range folders { 523 if folder.IsDir() { 524 files, err := ioutil.ReadDir(path + "/" + folder.Name()) 525 if err != nil { 526 log.Error("error reading template sub-dir", err) 527 return "", nil, err 528 } 529 530 for _, file := range files { 531 if !file.IsDir() && file.Name() == "template.json" { 532 data, err := ioutil.ReadFile(path + "/" + folder.Name() + "/template.json") 533 534 if err != nil { 535 log.Error("error reading template.json", err) 536 return "", nil, err 537 } 538 539 var config = templateConfig{} 540 err = json.Unmarshal(data, &config) 541 542 if err != nil { 543 log.Error("error parsing template.json", err) 544 return "", nil, err 545 } 546 547 if config.ID == ID { 548 template, err = ioutil.ReadFile(path + "/" + folder.Name() + "/template.docx") 549 return folder.Name(), template, err 550 } 551 } 552 } 553 } 554 } 555 556 return 557 }