mirror of
https://github.com/documize/community.git
synced 2025-07-20 21:59:42 +02:00
Support for document versioning
This commit is contained in:
parent
bc2cab5721
commit
a7a82d9fe3
9 changed files with 158 additions and 110 deletions
|
@ -65,7 +65,6 @@ func FilterCategoryProtected(docs []doc.Document, cats []category.Category, memb
|
||||||
|
|
||||||
// CopyDocument clones an existing document
|
// CopyDocument clones an existing document
|
||||||
func CopyDocument(ctx domain.RequestContext, s domain.Store, documentID string) (newDocumentID string, err error) {
|
func CopyDocument(ctx domain.RequestContext, s domain.Store, documentID string) (newDocumentID string, err error) {
|
||||||
|
|
||||||
doc, err := s.Document.Get(ctx, documentID)
|
doc, err := s.Document.Get(ctx, documentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "unable to fetch existing document")
|
err = errors.Wrap(err, "unable to fetch existing document")
|
||||||
|
@ -145,3 +144,32 @@ func CopyDocument(ctx domain.RequestContext, s domain.Store, documentID string)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FilterLastVersion returns the latest version of each document
|
||||||
|
// by removing all previous versions.
|
||||||
|
// If a document is not versioned, it is returned as-is.
|
||||||
|
func FilterLastVersion(docs []doc.Document) (filtered []doc.Document) {
|
||||||
|
filtered = []doc.Document{}
|
||||||
|
prev := make(map[string]bool)
|
||||||
|
|
||||||
|
for _, doc := range docs {
|
||||||
|
add := false
|
||||||
|
|
||||||
|
if doc.GroupID == "" {
|
||||||
|
add = true
|
||||||
|
} else {
|
||||||
|
if _, isExisting := prev[doc.GroupID]; !isExisting {
|
||||||
|
add = true
|
||||||
|
prev[doc.GroupID] = true
|
||||||
|
} else {
|
||||||
|
add = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if add {
|
||||||
|
filtered = append(filtered, doc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -44,9 +44,10 @@ type Handler struct {
|
||||||
Indexer indexer.Indexer
|
Indexer indexer.Indexer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get is an endpoint that returns the document-level information for a given documentID.
|
// Get is an endpoint that returns the document-level information for a
|
||||||
|
// given documentID.
|
||||||
func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
|
||||||
method := "document.get"
|
method := "document.Get"
|
||||||
ctx := domain.GetRequestContext(r)
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
id := request.Param(r, "documentID")
|
id := request.Param(r, "documentID")
|
||||||
|
@ -101,7 +102,7 @@ func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// DocumentLinks is an endpoint returning the links for a document.
|
// DocumentLinks is an endpoint returning the links for a document.
|
||||||
func (h *Handler) DocumentLinks(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) DocumentLinks(w http.ResponseWriter, r *http.Request) {
|
||||||
method := "document.links"
|
method := "document.DocumentLinks"
|
||||||
ctx := domain.GetRequestContext(r)
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
id := request.Param(r, "documentID")
|
id := request.Param(r, "documentID")
|
||||||
|
@ -142,7 +143,8 @@ func (h *Handler) BySpace(w http.ResponseWriter, r *http.Request) {
|
||||||
// get user permissions
|
// get user permissions
|
||||||
viewDrafts := permission.CanViewDrafts(ctx, *h.Store, spaceID)
|
viewDrafts := permission.CanViewDrafts(ctx, *h.Store, spaceID)
|
||||||
|
|
||||||
// get complete list of documents
|
// Get complete list of documents regardless of category permission
|
||||||
|
// and versioning.
|
||||||
documents, err := h.Store.Document.GetBySpace(ctx, spaceID)
|
documents, err := h.Store.Document.GetBySpace(ctx, spaceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
|
@ -150,21 +152,25 @@ func (h *Handler) BySpace(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort by title
|
// Sort by title.
|
||||||
sort.Sort(doc.ByTitle(documents))
|
sort.Sort(doc.ByTitle(documents))
|
||||||
|
|
||||||
// remove documents that cannot be seen due to lack of category view/access permission
|
// Remove documents that cannot be seen due to lack of
|
||||||
|
// category view/access permission.
|
||||||
cats, err := h.Store.Category.GetBySpace(ctx, spaceID)
|
cats, err := h.Store.Category.GetBySpace(ctx, spaceID)
|
||||||
members, err := h.Store.Category.GetSpaceCategoryMembership(ctx, spaceID)
|
members, err := h.Store.Category.GetSpaceCategoryMembership(ctx, spaceID)
|
||||||
filtered := FilterCategoryProtected(documents, cats, members, viewDrafts)
|
filtered := FilterCategoryProtected(documents, cats, members, viewDrafts)
|
||||||
|
|
||||||
|
// Keep the latest version when faced with multiple versions.
|
||||||
|
filtered = FilterLastVersion(filtered)
|
||||||
|
|
||||||
response.WriteJSON(w, filtered)
|
response.WriteJSON(w, filtered)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates an existing document using the
|
// Update updates an existing document using the format described
|
||||||
// format described in NewDocumentModel() encoded as JSON in the request.
|
// in NewDocumentModel() encoded as JSON in the request.
|
||||||
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
method := "document.space"
|
method := "document.Update"
|
||||||
ctx := domain.GetRequestContext(r)
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
documentID := request.Param(r, "documentID")
|
documentID := request.Param(r, "documentID")
|
||||||
|
@ -203,7 +209,7 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// if space changed for document, remove document categories
|
// If space changed for document, remove document categories.
|
||||||
oldDoc, err := h.Store.Document.Get(ctx, documentID)
|
oldDoc, err := h.Store.Document.Get(ctx, documentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
|
@ -224,7 +230,20 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record document being marked as archived
|
// If document part of versioned document group
|
||||||
|
// then document name must be applied to all documents
|
||||||
|
// in the group.
|
||||||
|
if len(d.GroupID) > 0 {
|
||||||
|
err = h.Store.Document.UpdateGroup(ctx, d)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Transaction.Rollback()
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record document being marked as archived.
|
||||||
if d.Lifecycle != oldDoc.Lifecycle && d.Lifecycle == workflow.LifecycleArchived {
|
if d.Lifecycle != oldDoc.Lifecycle && d.Lifecycle == workflow.LifecycleArchived {
|
||||||
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
||||||
LabelID: d.LabelID,
|
LabelID: d.LabelID,
|
||||||
|
@ -233,7 +252,7 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
ActivityType: activity.TypeArchived})
|
ActivityType: activity.TypeArchived})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record document being marked as draft
|
// Record document being marked as draft.
|
||||||
if d.Lifecycle != oldDoc.Lifecycle && d.Lifecycle == workflow.LifecycleDraft {
|
if d.Lifecycle != oldDoc.Lifecycle && d.Lifecycle == workflow.LifecycleDraft {
|
||||||
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
|
||||||
LabelID: d.LabelID,
|
LabelID: d.LabelID,
|
||||||
|
@ -246,7 +265,7 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
h.Store.Audit.Record(ctx, audit.EventTypeDocumentUpdate)
|
h.Store.Audit.Record(ctx, audit.EventTypeDocumentUpdate)
|
||||||
|
|
||||||
// Live document indexed for search
|
// Live document indexed for search.
|
||||||
if d.Lifecycle == workflow.LifecycleLive {
|
if d.Lifecycle == workflow.LifecycleLive {
|
||||||
a, _ := h.Store.Attachment.GetAttachments(ctx, documentID)
|
a, _ := h.Store.Attachment.GetAttachments(ctx, documentID)
|
||||||
go h.Indexer.IndexDocument(ctx, d, a)
|
go h.Indexer.IndexDocument(ctx, d, a)
|
||||||
|
@ -259,7 +278,7 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Delete is an endpoint that deletes a document specified by documentID.
|
// Delete is an endpoint that deletes a document specified by documentID.
|
||||||
func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||||
method := "document.delete"
|
method := "document.Delete"
|
||||||
ctx := domain.GetRequestContext(r)
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
documentID := request.Param(r, "documentID")
|
documentID := request.Param(r, "documentID")
|
||||||
|
@ -348,9 +367,10 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||||
response.WriteEmpty(w)
|
response.WriteEmpty(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchDocuments endpoint takes a list of keywords and returns a list of document references matching those keywords.
|
// SearchDocuments endpoint takes a list of keywords and returns a list of
|
||||||
|
// document references matching those keywords.
|
||||||
func (h *Handler) SearchDocuments(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) SearchDocuments(w http.ResponseWriter, r *http.Request) {
|
||||||
method := "document.search"
|
method := "document.SearchDocuments"
|
||||||
ctx := domain.GetRequestContext(r)
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
defer streamutil.Close(r.Body)
|
defer streamutil.Close(r.Body)
|
||||||
|
@ -467,12 +487,22 @@ func (h *Handler) FetchDocumentData(w http.ResponseWriter, r *http.Request) {
|
||||||
sp = []space.Space{}
|
sp = []space.Space{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get version information for this document.
|
||||||
|
v, err := h.Store.Document.GetVersions(ctx, document.GroupID)
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
h.Runtime.Log.Error(method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare response.
|
||||||
data := BulkDocumentData{}
|
data := BulkDocumentData{}
|
||||||
data.Document = document
|
data.Document = document
|
||||||
data.Permissions = record
|
data.Permissions = record
|
||||||
data.Roles = rolesRecord
|
data.Roles = rolesRecord
|
||||||
data.Links = l
|
data.Links = l
|
||||||
data.Spaces = sp
|
data.Spaces = sp
|
||||||
|
data.Versions = v
|
||||||
|
|
||||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -509,4 +539,5 @@ type BulkDocumentData struct {
|
||||||
Roles pm.DocumentRecord `json:"roles"`
|
Roles pm.DocumentRecord `json:"roles"`
|
||||||
Spaces []space.Space `json:"folders"`
|
Spaces []space.Space `json:"folders"`
|
||||||
Links []link.Link `json:"links"`
|
Links []link.Link `json:"links"`
|
||||||
|
Versions []doc.Version `json:"versions"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,20 +97,13 @@ func (s Scope) DocumentMeta(ctx domain.RequestContext, id string) (meta doc.Docu
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAll returns a slice containg all of the the documents for the client's organisation.
|
|
||||||
func (s Scope) GetAll() (ctx domain.RequestContext, documents []doc.Document, err error) {
|
|
||||||
err = s.Runtime.Db.Select(&documents, "SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template, protection, approval, created, revised FROM document WHERE orgid=? AND template=0 ORDER BY title", ctx.OrgID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
err = errors.Wrap(err, "select documents")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBySpace returns a slice containing the documents for a given space.
|
// GetBySpace returns a slice containing the documents for a given space.
|
||||||
// No attempt is made to hide documents that are protected
|
//
|
||||||
// by category permissions -- caller must filter as required.
|
// No attempt is made to hide documents that are protected by category
|
||||||
|
// permissions hence caller must filter as required.
|
||||||
|
//
|
||||||
|
// All versions of a document are returned, hence caller must
|
||||||
|
// decide what to do with them.
|
||||||
func (s Scope) GetBySpace(ctx domain.RequestContext, spaceID string) (documents []doc.Document, err error) {
|
func (s Scope) GetBySpace(ctx domain.RequestContext, spaceID string) (documents []doc.Document, err error) {
|
||||||
err = s.Runtime.Db.Select(&documents, `
|
err = s.Runtime.Db.Select(&documents, `
|
||||||
SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template,
|
SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template,
|
||||||
|
@ -125,7 +118,7 @@ func (s Scope) GetBySpace(ctx domain.RequestContext, spaceID string) (documents
|
||||||
AND p.who='role' AND p.location='space' AND p.refid=? AND p.action='view' AND (r.userid=? OR r.userid='0')
|
AND p.who='role' AND p.location='space' AND p.refid=? AND p.action='view' AND (r.userid=? OR r.userid='0')
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
ORDER BY title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, spaceID, ctx.OrgID, ctx.UserID, ctx.OrgID, spaceID, ctx.UserID)
|
ORDER BY title, versionorder`, ctx.OrgID, ctx.OrgID, ctx.OrgID, spaceID, ctx.OrgID, ctx.UserID, ctx.OrgID, spaceID, ctx.UserID)
|
||||||
|
|
||||||
if err == sql.ErrNoRows || len(documents) == 0 {
|
if err == sql.ErrNoRows || len(documents) == 0 {
|
||||||
err = nil
|
err = nil
|
||||||
|
@ -138,35 +131,6 @@ func (s Scope) GetBySpace(ctx domain.RequestContext, spaceID string) (documents
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Templates returns a slice containing the documents available as templates to the client's organisation, in title order.
|
|
||||||
func (s Scope) Templates(ctx domain.RequestContext) (documents []doc.Document, err error) {
|
|
||||||
err = s.Runtime.Db.Select(&documents,
|
|
||||||
`SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template,
|
|
||||||
protection, approval, lifecycle, versioned, versionid, versionorder, groupid, created, revised
|
|
||||||
FROM document
|
|
||||||
WHERE orgid=? AND template=1 AND lifecycle=1
|
|
||||||
AND labelid IN
|
|
||||||
(
|
|
||||||
SELECT refid FROM label WHERE orgid=?
|
|
||||||
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
|
||||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' AND action='view'
|
|
||||||
UNION ALL
|
|
||||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND (r.userid=? OR r.userid='0')
|
|
||||||
))
|
|
||||||
)
|
|
||||||
ORDER BY title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
|
||||||
|
|
||||||
if err == sql.ErrNoRows || len(documents) == 0 {
|
|
||||||
err = nil
|
|
||||||
documents = []doc.Document{}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
err = errors.Wrap(err, "select document templates")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TemplatesBySpace returns a slice containing the documents available as templates for given space.
|
// TemplatesBySpace returns a slice containing the documents available as templates for given space.
|
||||||
func (s Scope) TemplatesBySpace(ctx domain.RequestContext, spaceID string) (documents []doc.Document, err error) {
|
func (s Scope) TemplatesBySpace(ctx domain.RequestContext, spaceID string) (documents []doc.Document, err error) {
|
||||||
err = s.Runtime.Db.Select(&documents,
|
err = s.Runtime.Db.Select(&documents,
|
||||||
|
@ -196,7 +160,9 @@ func (s Scope) TemplatesBySpace(ctx domain.RequestContext, spaceID string) (docu
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// PublicDocuments returns a slice of SitemapDocument records, holding documents in folders of type 1 (entity.TemplateTypePublic).
|
// PublicDocuments returns a slice of SitemapDocument records
|
||||||
|
// linking to documents in public spaces.
|
||||||
|
// These documents can then be seen by search crawlers.
|
||||||
func (s Scope) PublicDocuments(ctx domain.RequestContext, orgID string) (documents []doc.SitemapDocument, err error) {
|
func (s Scope) PublicDocuments(ctx domain.RequestContext, orgID string) (documents []doc.SitemapDocument, err error) {
|
||||||
err = s.Runtime.Db.Select(&documents,
|
err = s.Runtime.Db.Select(&documents,
|
||||||
`SELECT d.refid as documentid, d.title as document, d.revised as revised, l.refid as folderid, l.label as folder
|
`SELECT d.refid as documentid, d.title as document, d.revised as revised, l.refid as folderid, l.label as folder
|
||||||
|
@ -217,35 +183,6 @@ func (s Scope) PublicDocuments(ctx domain.RequestContext, orgID string) (documen
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// DocumentList returns a slice containing the documents available as templates to the client's organisation, in title order.
|
|
||||||
func (s Scope) DocumentList(ctx domain.RequestContext) (documents []doc.Document, err error) {
|
|
||||||
err = s.Runtime.Db.Select(&documents,
|
|
||||||
`SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template,
|
|
||||||
protection, approval, lifecycle, versioned, versionid, versionorder, groupid, created, revised
|
|
||||||
FROM document
|
|
||||||
WHERE orgid=? AND template=0 AND lifecycle=1
|
|
||||||
AND labelid IN
|
|
||||||
(
|
|
||||||
SELECT refid FROM label WHERE orgid=?
|
|
||||||
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
|
||||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' AND action='view'
|
|
||||||
UNION ALL
|
|
||||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND (r.userid=? OR r.userid='0')
|
|
||||||
))
|
|
||||||
)
|
|
||||||
ORDER BY title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
|
||||||
err = nil
|
|
||||||
documents = []doc.Document{}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
err = errors.Wrap(err, "select documents list")
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update changes the given document record to the new values, updates search information and audits the action.
|
// Update changes the given document record to the new values, updates search information and audits the action.
|
||||||
func (s Scope) Update(ctx domain.RequestContext, document doc.Document) (err error) {
|
func (s Scope) Update(ctx domain.RequestContext, document doc.Document) (err error) {
|
||||||
document.Revised = time.Now().UTC()
|
document.Revised = time.Now().UTC()
|
||||||
|
@ -255,11 +192,27 @@ func (s Scope) Update(ctx domain.RequestContext, document doc.Document) (err err
|
||||||
SET
|
SET
|
||||||
labelid=:labelid, userid=:userid, job=:job, location=:location, title=:title, excerpt=:excerpt, slug=:slug, tags=:tags, template=:template,
|
labelid=:labelid, userid=:userid, job=:job, location=:location, title=:title, excerpt=:excerpt, slug=:slug, tags=:tags, template=:template,
|
||||||
protection=:protection, approval=:approval, lifecycle=:lifecycle, versioned=:versioned, versionid=:versionid, versionorder=:versionorder, groupid=:groupid, revised=:revised
|
protection=:protection, approval=:approval, lifecycle=:lifecycle, versioned=:versioned, versionid=:versionid, versionorder=:versionorder, groupid=:groupid, revised=:revised
|
||||||
WHERE orgid=:orgid AND refid=:refid`,
|
WHERE orgid=:orgid AND refid=:refid`,
|
||||||
&document)
|
&document)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "execute update document")
|
err = errors.Wrap(err, "document.store.Update")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateGroup applies same values to all documents
|
||||||
|
// with the same group ID.
|
||||||
|
func (s Scope) UpdateGroup(ctx domain.RequestContext, d doc.Document) (err error) {
|
||||||
|
_, err = ctx.Transaction.Exec(`UPDATE document SET title=?, excerpt=? WHERE orgid=? AND groupid=?`,
|
||||||
|
d.Title, d.Excerpt, ctx.OrgID, d.GroupID)
|
||||||
|
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "document.store.UpdateTitle")
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -341,3 +294,28 @@ func (s Scope) DeleteBySpace(ctx domain.RequestContext, spaceID string) (rows in
|
||||||
|
|
||||||
return b.DeleteConstrained(ctx.Transaction, "document", ctx.OrgID, spaceID)
|
return b.DeleteConstrained(ctx.Transaction, "document", ctx.OrgID, spaceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetVersions returns a slice containing the documents for a given space.
|
||||||
|
//
|
||||||
|
// No attempt is made to hide documents that are protected by category
|
||||||
|
// permissions hence caller must filter as required.
|
||||||
|
//
|
||||||
|
// All versions of a document are returned, hence caller must
|
||||||
|
// decide what to do with them.
|
||||||
|
func (s Scope) GetVersions(ctx domain.RequestContext, groupID string) (v []doc.Version, err error) {
|
||||||
|
err = s.Runtime.Db.Select(&v, `
|
||||||
|
SELECT versionid, refid as documentid
|
||||||
|
FROM document
|
||||||
|
WHERE orgid=? AND groupid=?
|
||||||
|
ORDER BY versionorder`, ctx.OrgID, groupID)
|
||||||
|
|
||||||
|
if err == sql.ErrNoRows || len(v) == 0 {
|
||||||
|
err = nil
|
||||||
|
v = []doc.Version{}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "document.store.GetVersions")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -168,18 +168,17 @@ type AuditStorer interface {
|
||||||
type DocumentStorer interface {
|
type DocumentStorer interface {
|
||||||
Add(ctx RequestContext, document doc.Document) (err error)
|
Add(ctx RequestContext, document doc.Document) (err error)
|
||||||
Get(ctx RequestContext, id string) (document doc.Document, err error)
|
Get(ctx RequestContext, id string) (document doc.Document, err error)
|
||||||
GetAll() (ctx RequestContext, documents []doc.Document, err error)
|
|
||||||
GetBySpace(ctx RequestContext, spaceID string) (documents []doc.Document, err error)
|
GetBySpace(ctx RequestContext, spaceID string) (documents []doc.Document, err error)
|
||||||
DocumentList(ctx RequestContext) (documents []doc.Document, err error)
|
|
||||||
Templates(ctx RequestContext) (documents []doc.Document, err error)
|
|
||||||
TemplatesBySpace(ctx RequestContext, spaceID string) (documents []doc.Document, err error)
|
TemplatesBySpace(ctx RequestContext, spaceID string) (documents []doc.Document, err error)
|
||||||
DocumentMeta(ctx RequestContext, id string) (meta doc.DocumentMeta, err error)
|
DocumentMeta(ctx RequestContext, id string) (meta doc.DocumentMeta, err error)
|
||||||
PublicDocuments(ctx RequestContext, orgID string) (documents []doc.SitemapDocument, err error)
|
PublicDocuments(ctx RequestContext, orgID string) (documents []doc.SitemapDocument, err error)
|
||||||
Update(ctx RequestContext, document doc.Document) (err error)
|
Update(ctx RequestContext, document doc.Document) (err error)
|
||||||
|
UpdateGroup(ctx RequestContext, document doc.Document) (err error)
|
||||||
ChangeDocumentSpace(ctx RequestContext, document, space string) (err error)
|
ChangeDocumentSpace(ctx RequestContext, document, space string) (err error)
|
||||||
MoveDocumentSpace(ctx RequestContext, id, move string) (err error)
|
MoveDocumentSpace(ctx RequestContext, id, move string) (err error)
|
||||||
Delete(ctx RequestContext, documentID string) (rows int64, err error)
|
Delete(ctx RequestContext, documentID string) (rows int64, err error)
|
||||||
DeleteBySpace(ctx RequestContext, spaceID string) (rows int64, err error)
|
DeleteBySpace(ctx RequestContext, spaceID string) (rows int64, err error)
|
||||||
|
GetVersions(ctx RequestContext, groupID string) (v []doc.Version, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SettingStorer defines required methods for persisting global and user level settings
|
// SettingStorer defines required methods for persisting global and user level settings
|
||||||
|
|
|
@ -43,7 +43,8 @@ export default Route.extend(AuthenticatedRouteMixin, {
|
||||||
sections: this.modelFor('document').sections,
|
sections: this.modelFor('document').sections,
|
||||||
permissions: this.modelFor('document').permissions,
|
permissions: this.modelFor('document').permissions,
|
||||||
roles: this.modelFor('document').roles,
|
roles: this.modelFor('document').roles,
|
||||||
blocks: this.modelFor('document').blocks
|
blocks: this.modelFor('document').blocks,
|
||||||
|
versions: this.modelFor('document').versions
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -57,10 +58,11 @@ export default Route.extend(AuthenticatedRouteMixin, {
|
||||||
controller.set('permissions', model.permissions);
|
controller.set('permissions', model.permissions);
|
||||||
controller.set('roles', model.roles);
|
controller.set('roles', model.roles);
|
||||||
controller.set('blocks', model.blocks);
|
controller.set('blocks', model.blocks);
|
||||||
|
controller.set('versions', model.versions);
|
||||||
},
|
},
|
||||||
|
|
||||||
activate: function() {
|
activate: function () {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
window.scrollTo(0,0);
|
window.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{{toolbar/nav-bar}}
|
{{toolbar/nav-bar}} {{toolbar/for-document document=document spaces=folders space=folder
|
||||||
|
permissions=permissions roles=roles tab=tab versions=versions
|
||||||
{{toolbar/for-document document=document spaces=folders space=folder permissions=permissions roles=roles tab=tab
|
|
||||||
onDocumentDelete=(action 'onDocumentDelete')
|
onDocumentDelete=(action 'onDocumentDelete')
|
||||||
onSaveTemplate=(action 'onSaveTemplate')
|
onSaveTemplate=(action 'onSaveTemplate')
|
||||||
onSaveDocument=(action 'onSaveDocument')
|
onSaveDocument=(action 'onSaveDocument')
|
||||||
|
@ -10,9 +9,10 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
{{document/document-heading document=document permissions=permissions
|
{{document/document-heading document=document permissions=permissions
|
||||||
|
versions=versions
|
||||||
onSaveDocument=(action 'onSaveDocument')}}
|
onSaveDocument=(action 'onSaveDocument')}}
|
||||||
|
{{document/document-meta document=document folder=folder folders=folders
|
||||||
{{document/document-meta document=document folder=folder folders=folders permissions=permissions pages=pages
|
permissions=permissions pages=pages versions=versions
|
||||||
onSaveDocument=(action 'onSaveDocument')}}
|
onSaveDocument=(action 'onSaveDocument')}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -32,6 +32,7 @@ export default Route.extend(AuthenticatedRouteMixin, {
|
||||||
this.set('permissions', data.permissions);
|
this.set('permissions', data.permissions);
|
||||||
this.set('roles', data.roles);
|
this.set('roles', data.roles);
|
||||||
this.set('links', data.links);
|
this.set('links', data.links);
|
||||||
|
this.set('versions', data.versions);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -45,13 +46,14 @@ export default Route.extend(AuthenticatedRouteMixin, {
|
||||||
permissions: this.get('permissions'),
|
permissions: this.get('permissions'),
|
||||||
roles: this.get('roles'),
|
roles: this.get('roles'),
|
||||||
links: this.get('links'),
|
links: this.get('links'),
|
||||||
|
versions: this.get('versions'),
|
||||||
sections: this.get('sectionService').getAll(),
|
sections: this.get('sectionService').getAll(),
|
||||||
blocks: this.get('sectionService').getSpaceBlocks(this.get('folder.id'))
|
blocks: this.get('sectionService').getSpaceBlocks(this.get('folder.id'))
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
error(error /*, transition*/ ) {
|
error(error /*, transition*/) {
|
||||||
if (error) {
|
if (error) {
|
||||||
this.transitionTo('/not-found');
|
this.transitionTo('/not-found');
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -334,6 +334,7 @@ export default Service.extend({
|
||||||
folders: [],
|
folders: [],
|
||||||
folder: {},
|
folder: {},
|
||||||
links: [],
|
links: [],
|
||||||
|
versions: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
let doc = this.get('store').normalize('document', response.document);
|
let doc = this.get('store').normalize('document', response.document);
|
||||||
|
@ -357,6 +358,7 @@ export default Service.extend({
|
||||||
data.folders = folders;
|
data.folders = folders;
|
||||||
data.folder = folders.findBy('id', doc.get('folderId'));
|
data.folder = folders.findBy('id', doc.get('folderId'));
|
||||||
data.links = response.links;
|
data.links = response.links;
|
||||||
|
data.versions = response.versions;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
|
|
|
@ -94,3 +94,9 @@ type SitemapDocument struct {
|
||||||
Folder string
|
Folder string
|
||||||
Revised time.Time
|
Revised time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Version points to a version of a document.
|
||||||
|
type Version struct {
|
||||||
|
VersionID string `json:"versionId"`
|
||||||
|
DocumentID string `json:"documentId"`
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue