mirror of
https://github.com/documize/community.git
synced 2025-07-20 21:59:42 +02:00
parent
2b66d0096a
commit
e014f5b5c1
18 changed files with 541 additions and 88 deletions
|
@ -14,6 +14,7 @@ package document
|
|||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"sort"
|
||||
|
@ -88,18 +89,12 @@ func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
err = h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
||||
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
||||
SpaceID: document.SpaceID,
|
||||
DocumentID: document.RefID,
|
||||
SourceType: activity.SourceTypeDocument,
|
||||
ActivityType: activity.TypeRead})
|
||||
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
}
|
||||
|
||||
|
@ -190,10 +185,26 @@ func (h *Handler) BySpace(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
// Sort document list by title.
|
||||
sort.Sort(doc.ByName(filtered))
|
||||
sortedDocs := doc.SortedDocs{}
|
||||
|
||||
response.WriteJSON(w, filtered)
|
||||
for j := range filtered {
|
||||
if filtered[j].Sequence == doc.Unsequenced {
|
||||
sortedDocs.Unpinned = append(sortedDocs.Unpinned, filtered[j])
|
||||
} else {
|
||||
sortedDocs.Pinned = append(sortedDocs.Pinned, filtered[j])
|
||||
}
|
||||
}
|
||||
|
||||
// Sort document list by title.
|
||||
sort.Sort(doc.ByName(sortedDocs.Unpinned))
|
||||
|
||||
// Sort document list by sequence.
|
||||
sort.Sort(doc.BySeq(sortedDocs.Pinned))
|
||||
|
||||
final := sortedDocs.Pinned
|
||||
final = append(final, sortedDocs.Unpinned...)
|
||||
|
||||
response.WriteJSON(w, final)
|
||||
}
|
||||
|
||||
// Update updates an existing document using the format described
|
||||
|
@ -249,7 +260,7 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if oldDoc.SpaceID != d.SpaceID {
|
||||
h.Store.Category.RemoveDocumentCategories(ctx, d.RefID)
|
||||
_, _ = h.Store.Category.RemoveDocumentCategories(ctx, d.RefID)
|
||||
err = h.Store.Document.MoveActivity(ctx, documentID, oldDoc.SpaceID, d.SpaceID)
|
||||
if err != nil {
|
||||
h.Runtime.Rollback(ctx.Transaction)
|
||||
|
@ -312,9 +323,9 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
h.Runtime.Commit(ctx.Transaction)
|
||||
|
||||
h.Store.Space.SetStats(ctx, d.SpaceID)
|
||||
_ = h.Store.Space.SetStats(ctx, d.SpaceID)
|
||||
if oldDoc.SpaceID != d.SpaceID {
|
||||
h.Store.Space.SetStats(ctx, oldDoc.SpaceID)
|
||||
_ = h.Store.Space.SetStats(ctx, oldDoc.SpaceID)
|
||||
}
|
||||
|
||||
h.Store.Audit.Record(ctx, audit.EventTypeDocumentUpdate)
|
||||
|
@ -480,18 +491,13 @@ func (h *Handler) SearchDocuments(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
err = h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
||||
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
||||
SpaceID: "",
|
||||
DocumentID: "",
|
||||
Metadata: options.Keywords,
|
||||
SourceType: activity.SourceTypeSearch,
|
||||
ActivityType: activity.TypeSearched})
|
||||
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
h.Runtime.Log.Error(method, err)
|
||||
}
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
}
|
||||
}
|
||||
|
@ -526,18 +532,13 @@ func (h *Handler) recordSearchActivity(ctx domain.RequestContext, q []search.Que
|
|||
}
|
||||
|
||||
if _, isExisting := prev[q[i].DocumentID]; !isExisting {
|
||||
err = h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
||||
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
||||
SpaceID: q[i].SpaceID,
|
||||
DocumentID: q[i].DocumentID,
|
||||
Metadata: keywords,
|
||||
SourceType: activity.SourceTypeSearch,
|
||||
ActivityType: activity.TypeSearched})
|
||||
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
h.Runtime.Log.Error(method, err)
|
||||
}
|
||||
|
||||
prev[q[i].DocumentID] = true
|
||||
}
|
||||
}
|
||||
|
@ -713,16 +714,11 @@ func (h *Handler) FetchDocumentData(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if document.Lifecycle == workflow.LifecycleLive {
|
||||
err = h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
||||
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
||||
SpaceID: document.SpaceID,
|
||||
DocumentID: document.RefID,
|
||||
SourceType: activity.SourceTypeDocument,
|
||||
ActivityType: activity.TypeRead})
|
||||
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
h.Runtime.Log.Error(method, err)
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
|
@ -786,7 +782,7 @@ func (h *Handler) Export(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(export))
|
||||
_, _ = w.Write([]byte(export))
|
||||
}
|
||||
|
||||
// Duplicate makes a copy of a document.
|
||||
|
@ -1014,3 +1010,219 @@ func (h *Handler) Duplicate(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
||||
// Pin marks existing document with sequence number so that it
|
||||
// appears at the top-most space view.
|
||||
func (h *Handler) Pin(w http.ResponseWriter, r *http.Request) {
|
||||
method := "document.Pin"
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
documentID := request.Param(r, "documentID")
|
||||
if len(documentID) == 0 {
|
||||
response.WriteMissingDataError(w, method, "documentID")
|
||||
return
|
||||
}
|
||||
|
||||
var ok bool
|
||||
ctx.Transaction, ok = h.Runtime.StartTx(sql.LevelReadUncommitted)
|
||||
if !ok {
|
||||
h.Runtime.Log.Info("unable to start transaction " + method)
|
||||
response.WriteServerError(w, method, errors.New("unable to start transaction"))
|
||||
return
|
||||
}
|
||||
|
||||
d, err := h.Store.Document.Get(ctx, documentID)
|
||||
if err != nil {
|
||||
h.Runtime.Rollback(ctx.Transaction)
|
||||
response.WriteServerError(w, method, err)
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if !permission.CanManageSpace(ctx, *h.Store, d.SpaceID) {
|
||||
h.Runtime.Rollback(ctx.Transaction)
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
// Calculate the next sequence number for this newly pinned document.
|
||||
seq, err := h.Store.Document.PinSequence(ctx, d.SpaceID)
|
||||
if err != nil {
|
||||
h.Runtime.Rollback(ctx.Transaction)
|
||||
h.Runtime.Log.Error(method, err)
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.Store.Document.Pin(ctx, documentID, seq+1)
|
||||
if err != nil {
|
||||
h.Runtime.Rollback(ctx.Transaction)
|
||||
response.WriteServerError(w, method, err)
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
||||
SpaceID: d.SpaceID,
|
||||
DocumentID: documentID,
|
||||
SourceType: activity.SourceTypeDocument,
|
||||
ActivityType: activity.TypePinned})
|
||||
|
||||
h.Runtime.Commit(ctx.Transaction)
|
||||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
||||
// Unpin removes an existing document from the space pinned list.
|
||||
func (h *Handler) Unpin(w http.ResponseWriter, r *http.Request) {
|
||||
method := "document.Unpin"
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
documentID := request.Param(r, "documentID")
|
||||
if len(documentID) == 0 {
|
||||
response.WriteMissingDataError(w, method, "documentID")
|
||||
return
|
||||
}
|
||||
|
||||
var ok bool
|
||||
ctx.Transaction, ok = h.Runtime.StartTx(sql.LevelReadUncommitted)
|
||||
if !ok {
|
||||
h.Runtime.Log.Info("unable to start transaction " + method)
|
||||
response.WriteServerError(w, method, errors.New("unable to start transaction"))
|
||||
return
|
||||
}
|
||||
|
||||
d, err := h.Store.Document.Get(ctx, documentID)
|
||||
if err != nil {
|
||||
h.Runtime.Rollback(ctx.Transaction)
|
||||
response.WriteServerError(w, method, err)
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if !permission.CanManageSpace(ctx, *h.Store, d.SpaceID) {
|
||||
h.Runtime.Rollback(ctx.Transaction)
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.Store.Document.Unpin(ctx, documentID)
|
||||
if err != nil {
|
||||
h.Runtime.Rollback(ctx.Transaction)
|
||||
response.WriteServerError(w, method, err)
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
||||
SpaceID: d.SpaceID,
|
||||
DocumentID: documentID,
|
||||
SourceType: activity.SourceTypeDocument,
|
||||
ActivityType: activity.TypeUnpinned})
|
||||
|
||||
h.Runtime.Commit(ctx.Transaction)
|
||||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
||||
// PinMove moves pinned document up or down in the sequence.
|
||||
func (h *Handler) PinMove(w http.ResponseWriter, r *http.Request) {
|
||||
method := "document.PinMove"
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
documentID := request.Param(r, "documentID")
|
||||
if len(documentID) == 0 {
|
||||
response.WriteMissingDataError(w, method, "documentID")
|
||||
return
|
||||
}
|
||||
|
||||
direction := request.Query(r, "direction")
|
||||
if len(direction) == 0 {
|
||||
response.WriteMissingDataError(w, method, "direction")
|
||||
return
|
||||
}
|
||||
|
||||
var ok bool
|
||||
ctx.Transaction, ok = h.Runtime.StartTx(sql.LevelReadUncommitted)
|
||||
if !ok {
|
||||
h.Runtime.Log.Info("unable to start transaction " + method)
|
||||
response.WriteServerError(w, method, errors.New("unable to start transaction"))
|
||||
return
|
||||
}
|
||||
|
||||
d, err := h.Store.Document.Get(ctx, documentID)
|
||||
if err != nil {
|
||||
h.Runtime.Rollback(ctx.Transaction)
|
||||
response.WriteServerError(w, method, err)
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if !permission.CanManageSpace(ctx, *h.Store, d.SpaceID) {
|
||||
h.Runtime.Rollback(ctx.Transaction)
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
// Get all pinned documents in the space.
|
||||
pinnedDocs, err := h.Store.Document.Pinned(ctx, d.SpaceID)
|
||||
if err != nil {
|
||||
h.Runtime.Rollback(ctx.Transaction)
|
||||
h.Runtime.Log.Error(method, err)
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Sort document list by sequence.
|
||||
sort.Sort(doc.BySeq(pinnedDocs))
|
||||
|
||||
// Resequence the documents.
|
||||
for i := range pinnedDocs {
|
||||
if pinnedDocs[i].RefID == documentID {
|
||||
if direction == "u" {
|
||||
if i-1 >= 0 {
|
||||
me := pinnedDocs[i].Sequence
|
||||
target := pinnedDocs[i-1].Sequence
|
||||
|
||||
pinnedDocs[i-1].Sequence = me
|
||||
pinnedDocs[i].Sequence = target
|
||||
}
|
||||
}
|
||||
if direction == "d" {
|
||||
if i+1 < len(pinnedDocs) {
|
||||
me := pinnedDocs[i].Sequence
|
||||
target := pinnedDocs[i+1].Sequence
|
||||
|
||||
pinnedDocs[i+1].Sequence = me
|
||||
pinnedDocs[i].Sequence = target
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Sort document list by sequence.
|
||||
sort.Sort(doc.BySeq(pinnedDocs))
|
||||
|
||||
// Save the resequenced documents.
|
||||
for i := range pinnedDocs {
|
||||
err = h.Store.Document.Pin(ctx, pinnedDocs[i].RefID, i+1)
|
||||
if err != nil {
|
||||
h.Runtime.Rollback(ctx.Transaction)
|
||||
response.WriteServerError(w, method, err)
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
||||
SpaceID: d.SpaceID,
|
||||
DocumentID: documentID,
|
||||
SourceType: activity.SourceTypeDocument,
|
||||
ActivityType: activity.TypePinSequence})
|
||||
|
||||
h.Runtime.Commit(ctx.Transaction)
|
||||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue