1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-08-05 05:25:27 +02:00

Provide basis for document lifecycle

This commit is contained in:
Harvey Kandola 2018-03-15 17:11:53 +00:00
parent d9a9a828ed
commit ba52dfa11d
20 changed files with 350 additions and 154 deletions

View file

@ -13,10 +13,12 @@ package mysql
import (
"database/sql"
"fmt"
"time"
"github.com/documize/community/core/env"
"github.com/documize/community/domain"
"github.com/documize/community/domain/store/mysql"
"github.com/documize/community/model/activity"
"github.com/pkg/errors"
)
@ -69,3 +71,12 @@ func (s Scope) GetDocumentActivity(ctx domain.RequestContext, id string) (a []ac
return
}
// DeleteDocumentChangeActivity removes all entries for document changes (add, remove, update).
func (s Scope) DeleteDocumentChangeActivity(ctx domain.RequestContext, documentID string) (rows int64, err error) {
b := mysql.BaseQuery{}
rows, err = b.DeleteWhere(ctx.Transaction,
fmt.Sprintf("DELETE FROM useractivity WHERE orgid='%s' AND documentid='%s' AND (activitytype=1 OR activitytype=2 OR activitytype=3 OR activitytype=4 OR activitytype=7)", ctx.OrgID, documentID))
return
}

View file

@ -78,15 +78,18 @@ func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
return
}
err = h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: document.LabelID,
DocumentID: document.RefID,
SourceType: activity.SourceTypeDocument,
ActivityType: activity.TypeRead})
// draft mode does not record document views
if document.Lifecycle == workflow.LifecycleLive {
err = h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: document.LabelID,
DocumentID: document.RefID,
SourceType: activity.SourceTypeDocument,
ActivityType: activity.TypeRead})
if err != nil {
ctx.Transaction.Rollback()
h.Runtime.Log.Error(method, err)
if err != nil {
ctx.Transaction.Rollback()
h.Runtime.Log.Error(method, err)
}
}
ctx.Transaction.Commit()
@ -136,6 +139,9 @@ func (h *Handler) BySpace(w http.ResponseWriter, r *http.Request) {
return
}
// get user permissions
viewDrafts := permission.CanViewDrafts(ctx, *h.Store, spaceID)
// get complete list of documents
documents, err := h.Store.Document.GetBySpace(ctx, spaceID)
if err != nil {
@ -143,10 +149,8 @@ func (h *Handler) BySpace(w http.ResponseWriter, r *http.Request) {
h.Runtime.Log.Error(method, err)
return
}
if len(documents) == 0 {
documents = []doc.Document{}
}
// sort by title
sort.Sort(doc.ByTitle(documents))
// remove documents that cannot be seen due to lack of
@ -158,6 +162,17 @@ func (h *Handler) BySpace(w http.ResponseWriter, r *http.Request) {
for _, doc := range documents {
hasCategory := false
canSeeCategory := false
skip := false
// drafts included if user can see them
if doc.Lifecycle == workflow.LifecycleDraft && !viewDrafts {
skip = true
}
// archived never included
if doc.Lifecycle == workflow.LifecycleArchived {
skip = true
}
OUTER:
@ -173,7 +188,7 @@ func (h *Handler) BySpace(w http.ResponseWriter, r *http.Request) {
}
}
if !hasCategory || canSeeCategory {
if !skip && (!hasCategory || canSeeCategory) {
filtered = append(filtered, doc)
}
}
@ -248,9 +263,9 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
h.Store.Audit.Record(ctx, audit.EventTypeDocumentUpdate)
a, _ := h.Store.Attachment.GetAttachments(ctx, documentID)
// Live document indexed for search
if d.Lifecycle == workflow.LifecycleLive {
a, _ := h.Store.Attachment.GetAttachments(ctx, documentID)
go h.Indexer.IndexDocument(ctx, d, a)
} else {
go h.Indexer.DeleteDocument(ctx, d.RefID)
@ -332,11 +347,14 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
h.Store.Link.MarkOrphanDocumentLink(ctx, documentID)
h.Store.Link.DeleteSourceDocumentLinks(ctx, documentID)
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: doc.LabelID,
DocumentID: documentID,
SourceType: activity.SourceTypeDocument,
ActivityType: activity.TypeDeleted})
// Draft actions are not logged
if doc.Lifecycle == workflow.LifecycleLive {
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: doc.LabelID,
DocumentID: documentID,
SourceType: activity.SourceTypeDocument,
ActivityType: activity.TypeDeleted})
}
ctx.Transaction.Commit()
@ -417,6 +435,12 @@ func (h *Handler) FetchDocumentData(w http.ResponseWriter, r *http.Request) {
return
}
// Don't serve archived document
if document.Lifecycle == workflow.LifecycleArchived {
response.WriteForbiddenError(w)
return
}
// permissions
perms, err := h.Store.Permission.GetUserSpacePermissions(ctx, document.LabelID)
if err != nil && err != sql.ErrNoRows {
@ -474,15 +498,17 @@ func (h *Handler) FetchDocumentData(w http.ResponseWriter, r *http.Request) {
return
}
err = h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: document.LabelID,
DocumentID: document.RefID,
SourceType: activity.SourceTypeDocument,
ActivityType: activity.TypeRead})
if document.Lifecycle == workflow.LifecycleLive {
err = h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: document.LabelID,
DocumentID: document.RefID,
SourceType: activity.SourceTypeDocument,
ActivityType: activity.TypeRead})
if err != nil {
ctx.Transaction.Rollback()
h.Runtime.Log.Error(method, err)
if err != nil {
ctx.Transaction.Rollback()
h.Runtime.Log.Error(method, err)
}
}
ctx.Transaction.Commit()

View file

@ -164,12 +164,15 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
h.Store.Block.IncrementUsage(ctx, model.Page.BlockID)
}
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: doc.LabelID,
DocumentID: model.Page.DocumentID,
PageID: model.Page.RefID,
SourceType: activity.SourceTypePage,
ActivityType: activity.TypeCreated})
// Draft actions are not logged
if doc.Lifecycle == workflow.LifecycleLive {
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: doc.LabelID,
DocumentID: model.Page.DocumentID,
PageID: model.Page.RefID,
SourceType: activity.SourceTypePage,
ActivityType: activity.TypeCreated})
}
ctx.Transaction.Commit()
@ -433,12 +436,15 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
return
}
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: doc.LabelID,
DocumentID: model.Page.DocumentID,
PageID: model.Page.RefID,
SourceType: activity.SourceTypePage,
ActivityType: activity.TypeEdited})
// Draft edits are not logged
if doc.Lifecycle == workflow.LifecycleLive {
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: doc.LabelID,
DocumentID: model.Page.DocumentID,
PageID: model.Page.RefID,
SourceType: activity.SourceTypePage,
ActivityType: activity.TypeEdited})
}
h.Store.Audit.Record(ctx, audit.EventTypeSectionUpdate)
@ -562,12 +568,15 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
return
}
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: doc.LabelID,
DocumentID: documentID,
PageID: pageID,
SourceType: activity.SourceTypePage,
ActivityType: activity.TypeDeleted})
// Draft actions are not logged
if doc.Lifecycle == workflow.LifecycleLive {
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: doc.LabelID,
DocumentID: documentID,
PageID: pageID,
SourceType: activity.SourceTypePage,
ActivityType: activity.TypeDeleted})
}
go h.Indexer.DeleteContent(ctx, pageID)
@ -675,12 +684,15 @@ func (h *Handler) DeletePages(w http.ResponseWriter, r *http.Request) {
h.Store.Page.DeletePageRevisions(ctx, page.PageID)
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: doc.LabelID,
DocumentID: documentID,
PageID: page.PageID,
SourceType: activity.SourceTypePage,
ActivityType: activity.TypeDeleted})
// Draft actions are not logged
if doc.Lifecycle == workflow.LifecycleLive {
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: doc.LabelID,
DocumentID: documentID,
PageID: page.PageID,
SourceType: activity.SourceTypePage,
ActivityType: activity.TypeDeleted})
}
}
ctx.Transaction.Commit()
@ -940,13 +952,15 @@ func (h *Handler) Copy(w http.ResponseWriter, r *http.Request) {
h.Store.Block.IncrementUsage(ctx, model.Page.BlockID)
}
// Log action against target document
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: doc.LabelID,
DocumentID: targetID,
PageID: newPageID,
SourceType: activity.SourceTypePage,
ActivityType: activity.TypeCreated})
// Log t actions are not logged
if doc.Lifecycle == workflow.LifecycleLive {
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: doc.LabelID,
DocumentID: targetID,
PageID: newPageID,
SourceType: activity.SourceTypePage,
ActivityType: activity.TypeCreated})
}
ctx.Transaction.Commit()
@ -1189,12 +1203,15 @@ func (h *Handler) Rollback(w http.ResponseWriter, r *http.Request) {
return
}
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: doc.LabelID,
DocumentID: p.DocumentID,
PageID: p.RefID,
SourceType: activity.SourceTypePage,
ActivityType: activity.TypeReverted})
// Draft actions are not logged
if doc.Lifecycle == workflow.LifecycleLive {
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
LabelID: doc.LabelID,
DocumentID: p.DocumentID,
PageID: p.RefID,
SourceType: activity.SourceTypePage,
ActivityType: activity.TypeReverted})
}
ctx.Transaction.Commit()

View file

@ -165,6 +165,25 @@ func CanViewSpace(ctx domain.RequestContext, s domain.Store, spaceID string) boo
return false
}
// CanViewDrafts returns if the user has permission to view drafts in space.
func CanViewDrafts(ctx domain.RequestContext, s domain.Store, spaceID string) bool {
roles, err := s.Permission.GetUserSpacePermissions(ctx, spaceID)
if err == sql.ErrNoRows {
err = nil
}
if err != nil {
return false
}
for _, role := range roles {
if role.RefID == spaceID && role.Location == pm.LocationSpace && role.Scope == pm.ScopeRow &&
pm.ContainsPermission(role.Action, pm.DocumentLifecycle) {
return true
}
}
return false
}
// HasPermission returns if user can perform specified actions.
func HasPermission(ctx domain.RequestContext, s domain.Store, spaceID string, actions ...pm.Action) bool {
roles, err := s.Permission.GetUserSpacePermissions(ctx, spaceID)

View file

@ -217,6 +217,7 @@ type LinkStorer interface {
type ActivityStorer interface {
RecordUserActivity(ctx RequestContext, activity activity.UserActivity) (err error)
GetDocumentActivity(ctx RequestContext, id string) (a []activity.DocumentActivity, err error)
DeleteDocumentChangeActivity(ctx RequestContext, id string) (rows int64, err error)
}
// SearchStorer defines required methods for persisting search queries