1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-19 21:29:42 +02:00
documize/core/api/endpoint/document_endpoint.go

444 lines
9.7 KiB
Go
Raw Normal View History

2016-07-07 18:54:16 -07:00
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
package endpoint
import (
"database/sql"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
2016-07-20 15:58:37 +01:00
"github.com/documize/community/core/api/entity"
"github.com/documize/community/core/api/plugins"
"github.com/documize/community/core/api/request"
"github.com/documize/community/core/api/store"
"github.com/documize/community/core/log"
"github.com/documize/community/core/utility"
2016-07-07 18:54:16 -07:00
2017-04-04 17:55:17 +01:00
"github.com/documize/community/core/api/util"
2016-07-07 18:54:16 -07:00
"github.com/gorilla/mux"
)
// SearchDocuments endpoint takes a list of keywords and returns a list of document references matching those keywords.
func SearchDocuments(w http.ResponseWriter, r *http.Request) {
method := "SearchDocuments"
p := request.GetPersister(r)
query := r.URL.Query()
keywords := query.Get("keywords")
decoded, err := url.QueryUnescape(keywords)
log.IfErr(err)
results, err := p.SearchDocument(decoded)
if err != nil {
writeServerError(w, method, err)
return
}
// Put in slugs for easy UI display of search URL
for key, result := range results {
result.DocumentSlug = utility.MakeSlug(result.DocumentTitle)
result.FolderSlug = utility.MakeSlug(result.LabelName)
results[key] = result
}
if len(results) == 0 {
results = []entity.DocumentSearch{}
}
data, err := json.Marshal(results)
if err != nil {
writeJSONMarshalError(w, method, "search", err)
return
}
2017-05-04 12:31:52 +01:00
p.RecordEvent(entity.EventTypeSearch)
2016-07-07 18:54:16 -07:00
writeSuccessBytes(w, data)
}
// GetDocument is an endpoint that returns the document-level information for a given documentID.
func GetDocument(w http.ResponseWriter, r *http.Request) {
method := "GetDocument"
p := request.GetPersister(r)
params := mux.Vars(r)
id := params["documentID"]
if len(id) == 0 {
writeMissingDataError(w, method, "documentID")
return
}
document, err := p.GetDocument(id)
if err == sql.ErrNoRows {
writeNotFoundError(w, method, id)
return
}
if err != nil {
writeGeneralSQLError(w, method, err)
return
}
if !p.CanViewDocumentInFolder(document.LabelID) {
writeForbiddenError(w)
return
}
json, err := json.Marshal(document)
if err != nil {
writeJSONMarshalError(w, method, "document", err)
return
}
2017-01-28 20:38:56 -08:00
p.Context.Transaction, err = request.Db.Beginx()
if err != nil {
writeTransactionError(w, method, err)
return
}
2017-05-04 12:31:52 +01:00
_ = p.RecordUserActivity(entity.UserActivity{
2017-01-28 20:38:56 -08:00
LabelID: document.LabelID,
SourceID: document.RefID,
SourceType: entity.ActivitySourceTypeDocument,
ActivityType: entity.ActivityTypeRead})
2017-05-04 12:31:52 +01:00
p.RecordEvent(entity.EventTypeDocumentView)
2017-01-28 20:38:56 -08:00
log.IfErr(p.Context.Transaction.Commit())
2016-07-07 18:54:16 -07:00
writeSuccessBytes(w, json)
}
2017-04-04 17:55:17 +01:00
// GetDocumentActivity is an endpoint returning the activity logs for specified document.
func GetDocumentActivity(w http.ResponseWriter, r *http.Request) {
method := "GetDocumentActivity"
2016-07-07 18:54:16 -07:00
p := request.GetPersister(r)
params := mux.Vars(r)
2017-04-04 17:55:17 +01:00
id := params["documentID"]
2016-07-07 18:54:16 -07:00
if len(id) == 0 {
writeMissingDataError(w, method, "documentID")
return
}
2017-04-04 17:55:17 +01:00
a, err := p.GetDocumentActivity(id)
if err != nil && err != sql.ErrNoRows {
2016-07-07 18:54:16 -07:00
writeGeneralSQLError(w, method, err)
return
}
2017-04-04 17:55:17 +01:00
util.WriteJSON(w, a)
2016-07-07 18:54:16 -07:00
}
2016-11-11 17:42:49 -08:00
// GetDocumentLinks is an endpoint returning the links for a document.
func GetDocumentLinks(w http.ResponseWriter, r *http.Request) {
method := "GetDocumentLinks"
p := request.GetPersister(r)
params := mux.Vars(r)
id := params["documentID"]
if len(id) == 0 {
writeMissingDataError(w, method, "documentID")
return
}
oLinks, err := p.GetDocumentOutboundLinks(id)
if len(oLinks) == 0 {
oLinks = []entity.Link{}
}
if err != nil && err != sql.ErrNoRows {
writeGeneralSQLError(w, method, err)
return
}
json, err := json.Marshal(oLinks)
if err != nil {
writeJSONMarshalError(w, method, "link", err)
return
}
writeSuccessBytes(w, json)
}
2016-07-07 18:54:16 -07:00
// GetDocumentsByFolder is an endpoint that returns the documents in a given folder.
func GetDocumentsByFolder(w http.ResponseWriter, r *http.Request) {
method := "GetDocumentsByFolder"
p := request.GetPersister(r)
query := r.URL.Query()
folderID := query.Get("folder")
if len(folderID) == 0 {
writeMissingDataError(w, method, "folder")
return
}
if !p.CanViewFolder(folderID) {
writeForbiddenError(w)
return
}
documents, err := p.GetDocumentsByFolder(folderID)
if err != nil && err != sql.ErrNoRows {
writeServerError(w, method, err)
return
}
json, err := json.Marshal(documents)
if err != nil {
writeJSONMarshalError(w, method, "document", err)
return
}
writeSuccessBytes(w, json)
}
// GetDocumentsByTag is an endpoint that returns the documents with a given tag.
func GetDocumentsByTag(w http.ResponseWriter, r *http.Request) {
method := "GetDocumentsByTag"
p := request.GetPersister(r)
query := r.URL.Query()
tag := query.Get("tag")
if len(tag) == 0 {
writeMissingDataError(w, method, "tag")
return
}
documents, err := p.GetDocumentsByTag(tag)
if err != nil && err != sql.ErrNoRows {
writeServerError(w, method, err)
return
}
json, err := json.Marshal(documents)
if err != nil {
writeJSONMarshalError(w, method, "document", err)
return
}
writeSuccessBytes(w, json)
}
// DeleteDocument is an endpoint that deletes a document specified by documentID.
func DeleteDocument(w http.ResponseWriter, r *http.Request) {
method := "DeleteDocument"
p := request.GetPersister(r)
params := mux.Vars(r)
documentID := params["documentID"]
if len(documentID) == 0 {
writeMissingDataError(w, method, "documentID")
return
}
if !p.CanChangeDocument(documentID) {
writeForbiddenError(w)
return
}
2017-01-28 20:38:56 -08:00
doc, err := p.GetDocument(documentID)
if err != nil {
writeGeneralSQLError(w, method, err)
return
}
2016-07-07 18:54:16 -07:00
2017-01-28 20:38:56 -08:00
tx, err := request.Db.Beginx()
2016-07-07 18:54:16 -07:00
if err != nil {
writeTransactionError(w, method, err)
return
}
p.Context.Transaction = tx
_, err = p.DeleteDocument(documentID)
if err != nil {
log.IfErr(tx.Rollback())
writeGeneralSQLError(w, method, err)
return
}
2016-11-21 19:27:18 -08:00
_, err = p.DeletePinnedDocument(documentID)
if err != nil && err != sql.ErrNoRows {
log.IfErr(tx.Rollback())
writeServerError(w, method, err)
return
}
2017-01-28 20:38:56 -08:00
_ = p.RecordUserActivity(entity.UserActivity{
LabelID: doc.LabelID,
SourceID: documentID,
SourceType: entity.ActivitySourceTypeDocument,
ActivityType: entity.ActivityTypeDeleted})
2017-05-04 12:31:52 +01:00
p.RecordEvent(entity.EventTypeDocumentDelete)
2016-07-07 18:54:16 -07:00
log.IfErr(tx.Commit())
writeSuccessEmptyJSON(w)
}
// GetDocumentAsDocx returns a Word document.
func GetDocumentAsDocx(w http.ResponseWriter, r *http.Request) {
method := "GetDocumentAsDocx"
p := request.GetPersister(r)
params := mux.Vars(r)
documentID := params["documentID"]
if len(documentID) == 0 {
writeMissingDataError(w, method, "documentID")
return
}
document, err := p.GetDocument(documentID)
if err == sql.ErrNoRows {
writeNotFoundError(w, method, documentID)
return
}
if err != nil {
writeServerError(w, method, err)
return
}
if !p.CanViewDocumentInFolder(document.LabelID) {
writeForbiddenError(w)
return
}
pages, err := p.GetPages(documentID)
if err != nil {
writeServerError(w, method, err)
return
}
xtn := "html"
actions, err := plugins.Lib.Actions("Export")
if err == nil {
for _, x := range actions {
if x == "docx" { // only actually export a docx if we have the plugin
xtn = x
break
}
}
}
estLen := 0
for _, page := range pages {
estLen += len(page.Title) + len(page.Body)
}
html := make([]byte, 0, estLen*2) // should be far bigger than we need
html = append(html, []byte("<html><head></head><body>")...)
for _, page := range pages {
html = append(html, []byte(fmt.Sprintf("<h%d>", page.Level))...)
html = append(html, utility.EscapeHTMLcomplexCharsByte([]byte(page.Title))...)
html = append(html, []byte(fmt.Sprintf("</h%d>", page.Level))...)
html = append(html, utility.EscapeHTMLcomplexCharsByte([]byte(page.Body))...)
}
html = append(html, []byte("</body></html>")...)
export, err := store.ExportAs(xtn, string(html))
log.Error("store.ExportAs()", err)
w.Header().Set("Content-Disposition", "attachment; filename="+utility.MakeSlug(document.Title)+"."+xtn)
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(export.File)))
writeSuccessBytes(w, export.File)
}
// UpdateDocument updates an existing document using the
// format described in NewDocumentModel() encoded as JSON in the request.
func UpdateDocument(w http.ResponseWriter, r *http.Request) {
method := "UpdateDocument"
p := request.GetPersister(r)
if !p.Context.Editor {
w.WriteHeader(http.StatusForbidden)
return
}
params := mux.Vars(r)
documentID := params["documentID"]
if len(documentID) == 0 {
writeMissingDataError(w, method, "documentID")
return
}
if !p.CanChangeDocument(documentID) {
writeForbiddenError(w)
return
}
defer utility.Close(r.Body)
body, err := ioutil.ReadAll(r.Body)
if err != nil {
writePayloadError(w, method, err)
return
}
d := entity.Document{}
err = json.Unmarshal(body, &d)
if err != nil {
writeBadRequestError(w, method, "document")
return
}
d.RefID = documentID
tx, err := request.Db.Beginx()
if err != nil {
writeTransactionError(w, method, err)
return
}
p.Context.Transaction = tx
err = p.UpdateDocument(d)
if err != nil {
log.IfErr(tx.Rollback())
writeGeneralSQLError(w, method, err)
return
}
2017-05-04 12:31:52 +01:00
p.RecordEvent(entity.EventTypeDocumentUpdate)
2016-07-07 18:54:16 -07:00
log.IfErr(tx.Commit())
writeSuccessEmptyJSON(w)
}