github.com/elliott5/community@v0.14.1-0.20160709191136-823126fb026a/documize/api/endpoint/page_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  	"database/sql"
    16  	"encoding/json"
    17  	// "html/template"
    18  	"io/ioutil"
    19  	"net/http"
    20  	"strconv"
    21  
    22  	"github.com/documize/community/documize/api/endpoint/models"
    23  	"github.com/documize/community/documize/api/entity"
    24  	"github.com/documize/community/documize/api/request"
    25  	"github.com/documize/community/documize/api/util"
    26  	"github.com/documize/community/documize/section/provider"
    27  	"github.com/documize/community/wordsmith/log"
    28  	"github.com/documize/community/wordsmith/utility"
    29  
    30  	"github.com/gorilla/mux"
    31  )
    32  
    33  // AddDocumentPage inserts new section into document.
    34  func AddDocumentPage(w http.ResponseWriter, r *http.Request) {
    35  	method := "AddDocumentPage"
    36  	p := request.GetPersister(r)
    37  
    38  	params := mux.Vars(r)
    39  	documentID := params["documentID"]
    40  
    41  	if len(documentID) == 0 {
    42  		writeMissingDataError(w, method, "documentID")
    43  		return
    44  	}
    45  
    46  	if !p.CanChangeDocument(documentID) {
    47  		writeForbiddenError(w)
    48  		return
    49  	}
    50  
    51  	defer utility.Close(r.Body)
    52  	body, err := ioutil.ReadAll(r.Body)
    53  
    54  	if err != nil {
    55  		writeBadRequestError(w, method, "Bad payload")
    56  		return
    57  	}
    58  
    59  	model := new(models.PageModel)
    60  	err = json.Unmarshal(body, &model)
    61  
    62  	if err != nil {
    63  		writePayloadError(w, method, err)
    64  		return
    65  	}
    66  
    67  	if model.Page.DocumentID != documentID {
    68  		writeBadRequestError(w, method, "documentID mismatch")
    69  		return
    70  	}
    71  
    72  	if model.Meta.DocumentID != documentID {
    73  		writeBadRequestError(w, method, "documentID mismatch")
    74  		return
    75  	}
    76  
    77  	pageID := util.UniqueID()
    78  	model.Page.RefID = pageID
    79  	model.Meta.PageID = pageID
    80  	model.Page.SetDefaults()
    81  	model.Meta.SetDefaults()
    82  	model.Meta.OrgID = p.Context.OrgID
    83  	model.Meta.UserID = p.Context.UserID
    84  	// page.Title = template.HTMLEscapeString(page.Title)
    85  
    86  	tx, err := request.Db.Beginx()
    87  
    88  	if err != nil {
    89  		writeTransactionError(w, method, err)
    90  		return
    91  	}
    92  
    93  	p.Context.Transaction = tx
    94  
    95  	output, ok := provider.Render(model.Page.ContentType,
    96  		provider.NewContext(model.Meta.OrgID, model.Meta.UserID), model.Meta.Config, model.Meta.RawBody)
    97  	if !ok {
    98  		log.ErrorString("provider.Render could not find: " + model.Page.ContentType)
    99  	}
   100  
   101  	model.Page.Body = output
   102  
   103  	err = p.AddPage(*model)
   104  
   105  	if err != nil {
   106  		log.IfErr(tx.Rollback())
   107  		writeGeneralSQLError(w, method, err)
   108  		return
   109  	}
   110  
   111  	log.IfErr(tx.Commit())
   112  
   113  	newPage, err := p.GetPage(pageID)
   114  
   115  	json, err := json.Marshal(newPage)
   116  
   117  	if err != nil {
   118  		writeJSONMarshalError(w, method, "page", err)
   119  		return
   120  	}
   121  
   122  	writeSuccessBytes(w, json)
   123  }
   124  
   125  // GetDocumentPage gets specified page for document.
   126  func GetDocumentPage(w http.ResponseWriter, r *http.Request) {
   127  	method := "GetDocumentPage"
   128  	p := request.GetPersister(r)
   129  
   130  	params := mux.Vars(r)
   131  	documentID := params["documentID"]
   132  	pageID := params["pageID"]
   133  
   134  	if len(documentID) == 0 {
   135  		writeMissingDataError(w, method, "documentID")
   136  		return
   137  	}
   138  
   139  	if len(pageID) == 0 {
   140  		writeMissingDataError(w, method, "pageID")
   141  		return
   142  	}
   143  
   144  	if !p.CanViewDocument(documentID) {
   145  		writeForbiddenError(w)
   146  		return
   147  	}
   148  
   149  	page, err := p.GetPage(pageID)
   150  
   151  	if err == sql.ErrNoRows {
   152  		writeNotFoundError(w, method, documentID)
   153  		return
   154  	}
   155  
   156  	if err != nil {
   157  		writeGeneralSQLError(w, method, err)
   158  		return
   159  	}
   160  
   161  	if page.DocumentID != documentID {
   162  		writeBadRequestError(w, method, "documentID mismatch")
   163  		return
   164  	}
   165  
   166  	json, err := json.Marshal(page)
   167  
   168  	if err != nil {
   169  		writeJSONMarshalError(w, method, "document", err)
   170  		return
   171  	}
   172  
   173  	writeSuccessBytes(w, json)
   174  }
   175  
   176  // GetDocumentPages gets all pages for document.
   177  func GetDocumentPages(w http.ResponseWriter, r *http.Request) {
   178  	method := "GetDocumentPages"
   179  	p := request.GetPersister(r)
   180  
   181  	params := mux.Vars(r)
   182  	documentID := params["documentID"]
   183  
   184  	if len(documentID) == 0 {
   185  		writeMissingDataError(w, method, "documentID")
   186  		return
   187  	}
   188  
   189  	if !p.CanViewDocument(documentID) {
   190  		writeForbiddenError(w)
   191  		return
   192  	}
   193  
   194  	query := r.URL.Query()
   195  	content := query.Get("content")
   196  
   197  	var pages []entity.Page
   198  	var err error
   199  
   200  	if len(content) > 0 {
   201  		pages, err = p.GetPagesWithoutContent(documentID)
   202  	} else {
   203  		pages, err = p.GetPages(documentID)
   204  	}
   205  
   206  	if len(pages) == 0 {
   207  		pages = []entity.Page{}
   208  	}
   209  
   210  	if err != nil {
   211  		writeGeneralSQLError(w, method, err)
   212  		return
   213  	}
   214  
   215  	json, err := json.Marshal(pages)
   216  
   217  	if err != nil {
   218  		writeJSONMarshalError(w, method, "document", err)
   219  		return
   220  	}
   221  
   222  	writeSuccessBytes(w, json)
   223  }
   224  
   225  // GetDocumentPagesBatch gets specified pages for document.
   226  func GetDocumentPagesBatch(w http.ResponseWriter, r *http.Request) {
   227  	method := "GetDocumentPagesBatch"
   228  	p := request.GetPersister(r)
   229  
   230  	params := mux.Vars(r)
   231  	documentID := params["documentID"]
   232  
   233  	if len(documentID) == 0 {
   234  		writeMissingDataError(w, method, "documentID")
   235  		return
   236  	}
   237  
   238  	if !p.CanViewDocument(documentID) {
   239  		writeForbiddenError(w)
   240  		return
   241  	}
   242  
   243  	defer utility.Close(r.Body)
   244  	body, err := ioutil.ReadAll(r.Body)
   245  
   246  	if err != nil {
   247  		writePayloadError(w, method, err)
   248  		return
   249  	}
   250  
   251  	requestedPages := string(body)
   252  
   253  	pages, err := p.GetPagesWhereIn(documentID, requestedPages)
   254  
   255  	if err == sql.ErrNoRows {
   256  		writeNotFoundError(w, method, documentID)
   257  		return
   258  	}
   259  
   260  	if err != nil {
   261  		writeGeneralSQLError(w, method, err)
   262  		return
   263  	}
   264  
   265  	json, err := json.Marshal(pages)
   266  
   267  	if err != nil {
   268  		writeJSONMarshalError(w, method, "document", err)
   269  		return
   270  	}
   271  
   272  	writeSuccessBytes(w, json)
   273  }
   274  
   275  // DeleteDocumentPage deletes a page.
   276  func DeleteDocumentPage(w http.ResponseWriter, r *http.Request) {
   277  	method := "DeleteDocumentPage"
   278  	p := request.GetPersister(r)
   279  
   280  	params := mux.Vars(r)
   281  	documentID := params["documentID"]
   282  
   283  	if len(documentID) == 0 {
   284  		writeMissingDataError(w, method, "documentID")
   285  		return
   286  	}
   287  
   288  	pageID := params["pageID"]
   289  
   290  	if len(documentID) == 0 {
   291  		writeMissingDataError(w, method, "pageID")
   292  		return
   293  	}
   294  
   295  	if !p.CanChangeDocument(documentID) {
   296  		writeForbiddenError(w)
   297  		return
   298  	}
   299  
   300  	tx, err := request.Db.Beginx()
   301  
   302  	if err != nil {
   303  		writeTransactionError(w, method, err)
   304  		return
   305  	}
   306  
   307  	p.Context.Transaction = tx
   308  
   309  	_, err = p.DeletePage(documentID, pageID)
   310  
   311  	if err != nil {
   312  		log.IfErr(tx.Rollback())
   313  		writeGeneralSQLError(w, method, err)
   314  		return
   315  	}
   316  
   317  	log.IfErr(tx.Commit())
   318  
   319  	writeSuccessEmptyJSON(w)
   320  }
   321  
   322  // DeleteDocumentPages batch deletes pages.
   323  func DeleteDocumentPages(w http.ResponseWriter, r *http.Request) {
   324  	method := "DeleteDocumentPages"
   325  	p := request.GetPersister(r)
   326  
   327  	params := mux.Vars(r)
   328  	documentID := params["documentID"]
   329  
   330  	if len(documentID) == 0 {
   331  		writeMissingDataError(w, method, "documentID")
   332  		return
   333  	}
   334  
   335  	if !p.CanChangeDocument(documentID) {
   336  		writeForbiddenError(w)
   337  		return
   338  	}
   339  
   340  	defer utility.Close(r.Body)
   341  	body, err := ioutil.ReadAll(r.Body)
   342  
   343  	if err != nil {
   344  		writeBadRequestError(w, method, "Bad body")
   345  		return
   346  	}
   347  
   348  	model := new([]models.PageLevelRequestModel)
   349  	err = json.Unmarshal(body, &model)
   350  
   351  	if err != nil {
   352  		writePayloadError(w, method, err)
   353  		return
   354  	}
   355  
   356  	tx, err := request.Db.Beginx()
   357  
   358  	if err != nil {
   359  		writeTransactionError(w, method, err)
   360  		return
   361  	}
   362  
   363  	p.Context.Transaction = tx
   364  
   365  	for _, page := range *model {
   366  		_, err = p.DeletePage(documentID, page.PageID)
   367  
   368  		if err != nil {
   369  			log.IfErr(tx.Rollback())
   370  			writeGeneralSQLError(w, method, err)
   371  			return
   372  		}
   373  	}
   374  
   375  	log.IfErr(tx.Commit())
   376  
   377  	writeSuccessEmptyJSON(w)
   378  }
   379  
   380  // UpdateDocumentPage will persist changed page and note the fact
   381  // that this is a new revision. If the page is the first in a document
   382  // then the corresponding document title will also be changed.
   383  func UpdateDocumentPage(w http.ResponseWriter, r *http.Request) {
   384  	method := "UpdateDocumentPage"
   385  	p := request.GetPersister(r)
   386  
   387  	if !p.Context.Editor {
   388  		writeForbiddenError(w)
   389  		return
   390  	}
   391  
   392  	params := mux.Vars(r)
   393  	documentID := params["documentID"]
   394  
   395  	if len(documentID) == 0 {
   396  		writeMissingDataError(w, method, "documentID")
   397  		return
   398  	}
   399  
   400  	pageID := params["pageID"]
   401  
   402  	if len(pageID) == 0 {
   403  		writeMissingDataError(w, method, "pageID")
   404  		return
   405  	}
   406  
   407  	defer utility.Close(r.Body)
   408  	body, err := ioutil.ReadAll(r.Body)
   409  
   410  	if err != nil {
   411  		writeBadRequestError(w, method, "Bad request body")
   412  		return
   413  	}
   414  
   415  	model := new(models.PageModel)
   416  	err = json.Unmarshal(body, &model)
   417  
   418  	if err != nil {
   419  		writePayloadError(w, method, err)
   420  		return
   421  	}
   422  
   423  	if model.Page.RefID != pageID || model.Page.DocumentID != documentID {
   424  		writeBadRequestError(w, method, "id mismatch")
   425  		return
   426  	}
   427  
   428  	tx, err := request.Db.Beginx()
   429  
   430  	if err != nil {
   431  		writeTransactionError(w, method, err)
   432  		return
   433  	}
   434  
   435  	model.Page.SetDefaults()
   436  	model.Meta.SetDefaults()
   437  
   438  	oldPageMeta, err := p.GetPageMeta(pageID)
   439  
   440  	if err != nil {
   441  		log.Error("unable to fetch old pagemeta record", err)
   442  		writeBadRequestError(w, method, err.Error())
   443  		return
   444  	}
   445  
   446  	output, ok := provider.Render(model.Page.ContentType, provider.NewContext(model.Meta.OrgID, oldPageMeta.UserID), model.Meta.Config, model.Meta.RawBody)
   447  	if !ok {
   448  		log.ErrorString("provider.Render could not find: " + model.Page.ContentType)
   449  	}
   450  	model.Page.Body = output
   451  
   452  	p.Context.Transaction = tx
   453  
   454  	var skipRevision bool
   455  	skipRevision, err = strconv.ParseBool(r.URL.Query().Get("r"))
   456  
   457  	refID := util.UniqueID()
   458  	err = p.UpdatePage(model.Page, refID, p.Context.UserID, skipRevision)
   459  
   460  	if err != nil {
   461  		writeGeneralSQLError(w, method, err)
   462  		log.IfErr(tx.Rollback())
   463  		return
   464  	}
   465  
   466  	err = p.UpdatePageMeta(model.Meta, true) // change the UserID to the current one
   467  
   468  	log.IfErr(tx.Commit())
   469  
   470  	updatedPage, err := p.GetPage(pageID)
   471  
   472  	json, err := json.Marshal(updatedPage)
   473  
   474  	if err != nil {
   475  		writeJSONMarshalError(w, method, "page", err)
   476  		return
   477  	}
   478  
   479  	writeSuccessBytes(w, json)
   480  }
   481  
   482  // ChangeDocumentPageSequence will swap page sequence for a given number of pages.
   483  func ChangeDocumentPageSequence(w http.ResponseWriter, r *http.Request) {
   484  	method := "ChangeDocumentPageSequence"
   485  	p := request.GetPersister(r)
   486  
   487  	params := mux.Vars(r)
   488  	documentID := params["documentID"]
   489  
   490  	if len(documentID) == 0 {
   491  		writeMissingDataError(w, method, "documentID")
   492  		return
   493  	}
   494  
   495  	if !p.CanChangeDocument(documentID) {
   496  		writeForbiddenError(w)
   497  		return
   498  	}
   499  
   500  	defer utility.Close(r.Body)
   501  	body, err := ioutil.ReadAll(r.Body)
   502  
   503  	if err != nil {
   504  		writePayloadError(w, method, err)
   505  		return
   506  	}
   507  
   508  	model := new([]models.PageSequenceRequestModel)
   509  	err = json.Unmarshal(body, &model)
   510  
   511  	if err != nil {
   512  		writeBadRequestError(w, method, "bad payload")
   513  		return
   514  	}
   515  
   516  	tx, err := request.Db.Beginx()
   517  
   518  	if err != nil {
   519  		writeTransactionError(w, method, err)
   520  		return
   521  	}
   522  
   523  	p.Context.Transaction = tx
   524  
   525  	for _, page := range *model {
   526  		err = p.UpdatePageSequence(documentID, page.PageID, page.Sequence)
   527  
   528  		if err != nil {
   529  			log.IfErr(tx.Rollback())
   530  			writeGeneralSQLError(w, method, err)
   531  			return
   532  		}
   533  	}
   534  
   535  	log.IfErr(tx.Commit())
   536  
   537  	writeSuccessEmptyJSON(w)
   538  }
   539  
   540  // ChangeDocumentPageLevel handles page indent/outdent changes.
   541  func ChangeDocumentPageLevel(w http.ResponseWriter, r *http.Request) {
   542  	method := "ChangeDocumentPageLevel"
   543  	p := request.GetPersister(r)
   544  
   545  	params := mux.Vars(r)
   546  	documentID := params["documentID"]
   547  
   548  	if len(documentID) == 0 {
   549  		writeMissingDataError(w, method, "documentID")
   550  		return
   551  	}
   552  
   553  	if !p.CanChangeDocument(documentID) {
   554  		w.WriteHeader(http.StatusForbidden)
   555  		return
   556  	}
   557  
   558  	defer utility.Close(r.Body)
   559  	body, err := ioutil.ReadAll(r.Body)
   560  
   561  	if err != nil {
   562  		writePayloadError(w, method, err)
   563  		return
   564  	}
   565  
   566  	model := new([]models.PageLevelRequestModel)
   567  	err = json.Unmarshal(body, &model)
   568  
   569  	if err != nil {
   570  		writeBadRequestError(w, method, "bad payload")
   571  		return
   572  	}
   573  
   574  	tx, err := request.Db.Beginx()
   575  
   576  	if err != nil {
   577  		writeTransactionError(w, method, err)
   578  		return
   579  	}
   580  
   581  	p.Context.Transaction = tx
   582  
   583  	for _, page := range *model {
   584  		err = p.UpdatePageLevel(documentID, page.PageID, page.Level)
   585  
   586  		if err != nil {
   587  			log.IfErr(tx.Rollback())
   588  			writeGeneralSQLError(w, method, err)
   589  			return
   590  		}
   591  	}
   592  
   593  	log.IfErr(tx.Commit())
   594  
   595  	writeSuccessEmptyJSON(w)
   596  }
   597  
   598  // GetDocumentPageMeta gets page meta data for specified document page.
   599  func GetDocumentPageMeta(w http.ResponseWriter, r *http.Request) {
   600  	method := "GetDocumentPageMeta"
   601  	p := request.GetPersister(r)
   602  
   603  	params := mux.Vars(r)
   604  	documentID := params["documentID"]
   605  	pageID := params["pageID"]
   606  
   607  	if len(documentID) == 0 {
   608  		writeMissingDataError(w, method, "documentID")
   609  		return
   610  	}
   611  
   612  	if len(pageID) == 0 {
   613  		writeMissingDataError(w, method, "pageID")
   614  		return
   615  	}
   616  
   617  	if !p.CanViewDocument(documentID) {
   618  		writeForbiddenError(w)
   619  		return
   620  	}
   621  
   622  	meta, err := p.GetPageMeta(pageID)
   623  
   624  	if err == sql.ErrNoRows {
   625  		writeNotFoundError(w, method, pageID)
   626  		return
   627  	}
   628  
   629  	if err != nil {
   630  		writeGeneralSQLError(w, method, err)
   631  		return
   632  	}
   633  
   634  	if meta.DocumentID != documentID {
   635  		writeBadRequestError(w, method, "documentID mismatch")
   636  		return
   637  	}
   638  
   639  	json, err := json.Marshal(meta)
   640  
   641  	if err != nil {
   642  		writeJSONMarshalError(w, method, "pagemeta", err)
   643  		return
   644  	}
   645  
   646  	writeSuccessBytes(w, json)
   647  }