mirror of
https://github.com/documize/community.git
synced 2025-07-19 05:09:42 +02:00
Provider foundation for doc lifecycle and versions
This commit is contained in:
parent
4e32bffebe
commit
958f4d30b9
19 changed files with 918 additions and 782 deletions
|
@ -52,7 +52,7 @@ Space view.
|
||||||
|
|
||||||
## Latest version
|
## Latest version
|
||||||
|
|
||||||
Community edition: v1.58.0
|
Community edition: v1.59.0
|
||||||
|
|
||||||
## OS support
|
## OS support
|
||||||
|
|
||||||
|
|
|
@ -170,7 +170,7 @@ func setupAccount(rt *env.Runtime, completion onboardRequest, serial string) (er
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign permissions to space
|
// assign permissions to space
|
||||||
perms := []string{"view", "manage", "own", "doc-add", "doc-edit", "doc-delete", "doc-move", "doc-copy", "doc-template", "doc-approve"}
|
perms := []string{"view", "manage", "own", "doc-add", "doc-edit", "doc-delete", "doc-move", "doc-copy", "doc-template", "doc-approve", "doc-version", "doc-lifecycle"}
|
||||||
for _, p := range perms {
|
for _, p := range perms {
|
||||||
sql = fmt.Sprintf("insert into permission (orgid, who, whoid, action, scope, location, refid) values (\"%s\", 'user', \"%s\", \"%s\", 'object', 'space', \"%s\")", orgID, userID, p, labelID)
|
sql = fmt.Sprintf("insert into permission (orgid, who, whoid, action, scope, location, refid) values (\"%s\", 'user', \"%s\", \"%s\", 'object', 'space', \"%s\")", orgID, userID, p, labelID)
|
||||||
_, err = runSQL(rt, sql)
|
_, err = runSQL(rt, sql)
|
||||||
|
|
22
core/database/scripts/autobuild/db_00019.sql
Normal file
22
core/database/scripts/autobuild/db_00019.sql
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/* enterprise edition */
|
||||||
|
|
||||||
|
-- document lifecycle and versions
|
||||||
|
ALTER TABLE document ADD COLUMN `lifecycle` INT NOT NULL DEFAULT 1 AFTER `approval`;
|
||||||
|
ALTER TABLE document ADD COLUMN `versioned` INT NOT NULL DEFAULT 0 AFTER `lifecycle`;
|
||||||
|
ALTER TABLE document ADD COLUMN `versionid` VARCHAR(100) DEFAULT '' NOT NULL AFTER `versioned`;
|
||||||
|
ALTER TABLE document ADD COLUMN `versionorder` INT NOT NULL DEFAULT 0 AFTER `versionid`;
|
||||||
|
ALTER TABLE document ADD COLUMN `groupid` CHAR(16) NOT NULL COLLATE utf8_bin AFTER `versionorder`;
|
||||||
|
|
||||||
|
-- grant doc-lifecycle permission
|
||||||
|
INSERT INTO permission(orgid, who, whoid, action, scope, location, refid, created)
|
||||||
|
SELECT orgid, who, whoid, 'doc-lifecycle' AS action, scope, location, refid, created
|
||||||
|
FROM permission
|
||||||
|
WHERE action = 'doc-edit' OR action = 'doc-approve';
|
||||||
|
|
||||||
|
-- grant doc-versions permission
|
||||||
|
INSERT INTO permission(orgid, who, whoid, action, scope, location, refid, created)
|
||||||
|
SELECT orgid, who, whoid, 'doc-version' AS action, scope, location, refid, created
|
||||||
|
FROM permission
|
||||||
|
WHERE action = 'doc-edit' OR action = 'doc-approve';
|
||||||
|
|
||||||
|
-- deprecations
|
|
@ -30,6 +30,7 @@ import (
|
||||||
indexer "github.com/documize/community/domain/search"
|
indexer "github.com/documize/community/domain/search"
|
||||||
"github.com/documize/community/model/attachment"
|
"github.com/documize/community/model/attachment"
|
||||||
"github.com/documize/community/model/audit"
|
"github.com/documize/community/model/audit"
|
||||||
|
"github.com/documize/community/model/workflow"
|
||||||
uuid "github.com/nu7hatch/gouuid"
|
uuid "github.com/nu7hatch/gouuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -161,7 +162,12 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
a, _ := h.Store.Attachment.GetAttachments(ctx, documentID)
|
a, _ := h.Store.Attachment.GetAttachments(ctx, documentID)
|
||||||
d, _ := h.Store.Document.Get(ctx, documentID)
|
d, _ := h.Store.Document.Get(ctx, documentID)
|
||||||
go h.Indexer.IndexDocument(ctx, d, a)
|
|
||||||
|
if d.Lifecycle == workflow.LifecycleLive {
|
||||||
|
go h.Indexer.IndexDocument(ctx, d, a)
|
||||||
|
} else {
|
||||||
|
go h.Indexer.DeleteDocument(ctx, d.RefID)
|
||||||
|
}
|
||||||
|
|
||||||
response.WriteEmpty(w)
|
response.WriteEmpty(w)
|
||||||
}
|
}
|
||||||
|
@ -236,7 +242,12 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
all, _ := h.Store.Attachment.GetAttachments(ctx, documentID)
|
all, _ := h.Store.Attachment.GetAttachments(ctx, documentID)
|
||||||
d, _ := h.Store.Document.Get(ctx, documentID)
|
d, _ := h.Store.Document.Get(ctx, documentID)
|
||||||
go h.Indexer.IndexDocument(ctx, d, all)
|
|
||||||
|
if d.Lifecycle == workflow.LifecycleLive {
|
||||||
|
go h.Indexer.IndexDocument(ctx, d, all)
|
||||||
|
} else {
|
||||||
|
go h.Indexer.DeleteDocument(ctx, d.RefID)
|
||||||
|
}
|
||||||
|
|
||||||
response.WriteEmpty(w)
|
response.WriteEmpty(w)
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,7 +249,12 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
h.Store.Audit.Record(ctx, audit.EventTypeDocumentUpdate)
|
h.Store.Audit.Record(ctx, audit.EventTypeDocumentUpdate)
|
||||||
|
|
||||||
a, _ := h.Store.Attachment.GetAttachments(ctx, documentID)
|
a, _ := h.Store.Attachment.GetAttachments(ctx, documentID)
|
||||||
go h.Indexer.IndexDocument(ctx, d, a)
|
|
||||||
|
if d.Lifecycle == workflow.LifecycleLive {
|
||||||
|
go h.Indexer.IndexDocument(ctx, d, a)
|
||||||
|
} else {
|
||||||
|
go h.Indexer.DeleteDocument(ctx, d.RefID)
|
||||||
|
}
|
||||||
|
|
||||||
response.WriteEmpty(w)
|
response.WriteEmpty(w)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,13 +29,16 @@ type Scope struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add inserts the given document record into the document table and audits that it has been done.
|
// Add inserts the given document record into the document table and audits that it has been done.
|
||||||
func (s Scope) Add(ctx domain.RequestContext, document doc.Document) (err error) {
|
func (s Scope) Add(ctx domain.RequestContext, d doc.Document) (err error) {
|
||||||
document.OrgID = ctx.OrgID
|
d.OrgID = ctx.OrgID
|
||||||
document.Created = time.Now().UTC()
|
d.Created = time.Now().UTC()
|
||||||
document.Revised = document.Created // put same time in both fields
|
d.Revised = d.Created // put same time in both fields
|
||||||
|
|
||||||
_, err = ctx.Transaction.Exec("INSERT INTO document (refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template, protection, approval, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
_, err = ctx.Transaction.Exec(`
|
||||||
document.RefID, document.OrgID, document.LabelID, document.UserID, document.Job, document.Location, document.Title, document.Excerpt, document.Slug, document.Tags, document.Template, document.Protection, document.Approval, document.Created, document.Revised)
|
INSERT INTO document (refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template, protection, approval, lifecycle, versioned, versionid, versionorder, groupid, created, revised)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||||
|
d.RefID, d.OrgID, d.LabelID, d.UserID, d.Job, d.Location, d.Title, d.Excerpt, d.Slug, d.Tags,
|
||||||
|
d.Template, d.Protection, d.Approval, d.Lifecycle, d.Versioned, d.VersionID, d.VersionOrder, d.GroupID, d.Created, d.Revised)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "execuet insert document")
|
err = errors.Wrap(err, "execuet insert document")
|
||||||
|
@ -46,7 +49,11 @@ func (s Scope) Add(ctx domain.RequestContext, document doc.Document) (err error)
|
||||||
|
|
||||||
// Get fetches the document record with the given id fromt the document table and audits that it has been got.
|
// Get fetches the document record with the given id fromt the document table and audits that it has been got.
|
||||||
func (s Scope) Get(ctx domain.RequestContext, id string) (document doc.Document, err error) {
|
func (s Scope) Get(ctx domain.RequestContext, id string) (document doc.Document, err error) {
|
||||||
err = s.Runtime.Db.Get(&document, "SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template, protection, approval, created, revised FROM document WHERE orgid=? and refid=?",
|
err = s.Runtime.Db.Get(&document, `
|
||||||
|
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 refid=?`,
|
||||||
ctx.OrgID, id)
|
ctx.OrgID, id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -106,7 +113,8 @@ func (s Scope) GetAll() (ctx domain.RequestContext, documents []doc.Document, er
|
||||||
// by category permissions -- caller must filter as required.
|
// by category permissions -- caller must filter as required.
|
||||||
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, protection, approval, created, revised
|
SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template,
|
||||||
|
protection, approval, lifecycle, versioned, versionid, versionorder, groupid, created, revised
|
||||||
FROM document
|
FROM document
|
||||||
WHERE orgid=? AND template=0 AND labelid IN (
|
WHERE orgid=? AND template=0 AND labelid IN (
|
||||||
SELECT refid FROM label WHERE orgid=? AND refid IN
|
SELECT refid FROM label WHERE orgid=? AND refid IN
|
||||||
|
@ -119,8 +127,9 @@ func (s Scope) GetBySpace(ctx domain.RequestContext, spaceID string) (documents
|
||||||
)
|
)
|
||||||
ORDER BY title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, spaceID, ctx.OrgID, ctx.UserID, ctx.OrgID, spaceID, ctx.UserID)
|
ORDER BY title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, spaceID, ctx.OrgID, ctx.UserID, ctx.OrgID, spaceID, ctx.UserID)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows || len(documents) == 0 {
|
||||||
err = nil
|
err = nil
|
||||||
|
documents = []doc.Document{}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "select documents by space")
|
err = errors.Wrap(err, "select documents by space")
|
||||||
|
@ -132,7 +141,10 @@ func (s Scope) GetBySpace(ctx domain.RequestContext, spaceID string) (documents
|
||||||
// Templates returns a slice containing the documents available as templates to the client's organisation, in title order.
|
// 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) {
|
func (s Scope) Templates(ctx domain.RequestContext) (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, protection, approval, created, revised FROM document WHERE orgid=? AND template=1
|
`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
|
AND labelid IN
|
||||||
(
|
(
|
||||||
SELECT refid FROM label WHERE orgid=?
|
SELECT refid FROM label WHERE orgid=?
|
||||||
|
@ -144,6 +156,10 @@ func (s Scope) Templates(ctx domain.RequestContext) (documents []doc.Document, e
|
||||||
)
|
)
|
||||||
ORDER BY title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
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 {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "select document templates")
|
err = errors.Wrap(err, "select document templates")
|
||||||
}
|
}
|
||||||
|
@ -154,7 +170,10 @@ func (s Scope) Templates(ctx domain.RequestContext) (documents []doc.Document, e
|
||||||
// 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,
|
||||||
`SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template, protection, approval, created, revised FROM document WHERE orgid=? AND labelid=? AND template=1
|
`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 labelid=? AND template=1 ANd lifecycle=1
|
||||||
AND labelid IN
|
AND labelid IN
|
||||||
(
|
(
|
||||||
SELECT refid FROM label WHERE orgid=?
|
SELECT refid FROM label WHERE orgid=?
|
||||||
|
@ -170,7 +189,6 @@ func (s Scope) TemplatesBySpace(ctx domain.RequestContext, spaceID string) (docu
|
||||||
err = nil
|
err = nil
|
||||||
documents = []doc.Document{}
|
documents = []doc.Document{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "select space document templates")
|
err = errors.Wrap(err, "select space document templates")
|
||||||
}
|
}
|
||||||
|
@ -184,9 +202,14 @@ func (s Scope) PublicDocuments(ctx domain.RequestContext, orgID string) (documen
|
||||||
`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
|
||||||
FROM document d LEFT JOIN label l ON l.refid=d.labelid
|
FROM document d LEFT JOIN label l ON l.refid=d.labelid
|
||||||
WHERE d.orgid=?
|
WHERE d.orgid=?
|
||||||
AND l.type=1
|
AND l.type=1
|
||||||
AND d.template=0`, orgID)
|
AND d.lifecycle=1
|
||||||
|
AND d.template=0`, orgID)
|
||||||
|
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
err = nil
|
||||||
|
documents = []doc.SitemapDocument{}
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, fmt.Sprintf("execute GetPublicDocuments for org %s%s", orgID))
|
err = errors.Wrap(err, fmt.Sprintf("execute GetPublicDocuments for org %s%s", orgID))
|
||||||
}
|
}
|
||||||
|
@ -197,7 +220,10 @@ func (s Scope) PublicDocuments(ctx domain.RequestContext, orgID string) (documen
|
||||||
// DocumentList returns a slice containing the documents available as templates to the client's organisation, in title order.
|
// 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) {
|
func (s Scope) DocumentList(ctx domain.RequestContext) (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, protection, approval, created, revised FROM document WHERE orgid=? AND template=0
|
`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
|
AND labelid IN
|
||||||
(
|
(
|
||||||
SELECT refid FROM label WHERE orgid=?
|
SELECT refid FROM label WHERE orgid=?
|
||||||
|
@ -213,7 +239,6 @@ func (s Scope) DocumentList(ctx domain.RequestContext) (documents []doc.Document
|
||||||
err = nil
|
err = nil
|
||||||
documents = []doc.Document{}
|
documents = []doc.Document{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "select documents list")
|
err = errors.Wrap(err, "select documents list")
|
||||||
}
|
}
|
||||||
|
@ -225,7 +250,12 @@ func (s Scope) DocumentList(ctx domain.RequestContext) (documents []doc.Document
|
||||||
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()
|
||||||
|
|
||||||
_, err = ctx.Transaction.NamedExec("UPDATE document SET labelid=:labelid, userid=:userid, job=:job, location=:location, title=:title, excerpt=:excerpt, slug=:slug, tags=:tags, template=:template, protection=:protection, approval=:approval, revised=:revised WHERE orgid=:orgid AND refid=:refid",
|
_, err = ctx.Transaction.NamedExec(`
|
||||||
|
UPDATE document
|
||||||
|
SET
|
||||||
|
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
|
||||||
|
WHERE orgid=:orgid AND refid=:refid`,
|
||||||
&document)
|
&document)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -176,7 +176,12 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
||||||
h.Store.Audit.Record(ctx, audit.EventTypeSectionAdd)
|
h.Store.Audit.Record(ctx, audit.EventTypeSectionAdd)
|
||||||
|
|
||||||
np, _ := h.Store.Page.Get(ctx, pageID)
|
np, _ := h.Store.Page.Get(ctx, pageID)
|
||||||
go h.Indexer.IndexContent(ctx, np)
|
|
||||||
|
if doc.Lifecycle == workflow.LifecycleLive {
|
||||||
|
go h.Indexer.IndexContent(ctx, np)
|
||||||
|
} else {
|
||||||
|
go h.Indexer.DeleteDocument(ctx, doc.RefID)
|
||||||
|
}
|
||||||
|
|
||||||
response.WriteJSON(w, np)
|
response.WriteJSON(w, np)
|
||||||
}
|
}
|
||||||
|
@ -309,6 +314,7 @@ func (h *Handler) GetMeta(w http.ResponseWriter, r *http.Request) {
|
||||||
// Update will persist changed page and note the fact
|
// Update will persist changed page and note the fact
|
||||||
// that this is a new revision. If the page is the first in a document
|
// that this is a new revision. If the page is the first in a document
|
||||||
// then the corresponding document title will also be changed.
|
// then the corresponding document title will also be changed.
|
||||||
|
// Draft documents do not get revision entry.
|
||||||
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
method := "page.update"
|
method := "page.update"
|
||||||
ctx := domain.GetRequestContext(r)
|
ctx := domain.GetRequestContext(r)
|
||||||
|
@ -406,6 +412,11 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
skipRevision = true
|
skipRevision = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We only track revisions for live documents
|
||||||
|
if doc.Lifecycle != workflow.LifecycleLive {
|
||||||
|
skipRevision = true
|
||||||
|
}
|
||||||
|
|
||||||
err = h.Store.Page.Update(ctx, model.Page, refID, ctx.UserID, skipRevision)
|
err = h.Store.Page.Update(ctx, model.Page, refID, ctx.UserID, skipRevision)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
|
@ -470,7 +481,11 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
ctx.Transaction.Commit()
|
ctx.Transaction.Commit()
|
||||||
|
|
||||||
go h.Indexer.IndexContent(ctx, model.Page)
|
if doc.Lifecycle == workflow.LifecycleLive {
|
||||||
|
go h.Indexer.IndexContent(ctx, model.Page)
|
||||||
|
} else {
|
||||||
|
go h.Indexer.DeleteDocument(ctx, doc.RefID)
|
||||||
|
}
|
||||||
|
|
||||||
updatedPage, err := h.Store.Page.Get(ctx, pageID)
|
updatedPage, err := h.Store.Page.Get(ctx, pageID)
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ import (
|
||||||
"github.com/documize/community/model/page"
|
"github.com/documize/community/model/page"
|
||||||
pm "github.com/documize/community/model/permission"
|
pm "github.com/documize/community/model/permission"
|
||||||
"github.com/documize/community/model/template"
|
"github.com/documize/community/model/template"
|
||||||
|
"github.com/documize/community/model/workflow"
|
||||||
uuid "github.com/nu7hatch/gouuid"
|
uuid "github.com/nu7hatch/gouuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -377,7 +378,12 @@ func (h *Handler) Use(w http.ResponseWriter, r *http.Request) {
|
||||||
event.Handler().Publish(string(event.TypeAddDocument), nd.Title)
|
event.Handler().Publish(string(event.TypeAddDocument), nd.Title)
|
||||||
|
|
||||||
a, _ := h.Store.Attachment.GetAttachments(ctx, documentID)
|
a, _ := h.Store.Attachment.GetAttachments(ctx, documentID)
|
||||||
go h.Indexer.IndexDocument(ctx, nd, a)
|
|
||||||
|
if nd.Lifecycle == workflow.LifecycleLive {
|
||||||
|
go h.Indexer.IndexDocument(ctx, nd, a)
|
||||||
|
} else {
|
||||||
|
go h.Indexer.DeleteDocument(ctx, d.RefID)
|
||||||
|
}
|
||||||
|
|
||||||
response.WriteJSON(w, nd)
|
response.WriteJSON(w, nd)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ func main() {
|
||||||
// product details
|
// product details
|
||||||
rt.Product = env.ProdInfo{}
|
rt.Product = env.ProdInfo{}
|
||||||
rt.Product.Major = "1"
|
rt.Product.Major = "1"
|
||||||
rt.Product.Minor = "58"
|
rt.Product.Minor = "59"
|
||||||
rt.Product.Patch = "0"
|
rt.Product.Patch = "0"
|
||||||
rt.Product.Version = fmt.Sprintf("%s.%s.%s", rt.Product.Major, rt.Product.Minor, rt.Product.Patch)
|
rt.Product.Version = fmt.Sprintf("%s.%s.%s", rt.Product.Major, rt.Product.Minor, rt.Product.Patch)
|
||||||
rt.Product.Edition = "Community"
|
rt.Product.Edition = "Community"
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -93,6 +93,8 @@ export default Component.extend(ModalMixin, {
|
||||||
documentCopy: false,
|
documentCopy: false,
|
||||||
documentTemplate: false,
|
documentTemplate: false,
|
||||||
documentApprove: false,
|
documentApprove: false,
|
||||||
|
documentLifecycle: false,
|
||||||
|
documentVersion: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let rec = this.get('store').normalize('space-permission', raw);
|
let rec = this.get('store').normalize('space-permission', raw);
|
||||||
|
@ -132,7 +134,8 @@ export default Component.extend(ModalMixin, {
|
||||||
let hasEveryone = _.find(permissions, (permission) => {
|
let hasEveryone = _.find(permissions, (permission) => {
|
||||||
return permission.get('whoId') === constants.EveryoneUserId &&
|
return permission.get('whoId') === constants.EveryoneUserId &&
|
||||||
(permission.get('spaceView') || permission.get('documentAdd') || permission.get('documentEdit') || permission.get('documentDelete') ||
|
(permission.get('spaceView') || permission.get('documentAdd') || permission.get('documentEdit') || permission.get('documentDelete') ||
|
||||||
permission.get('documentMove') || permission.get('documentCopy') || permission.get('documentTemplate') || permission.get('documentApprove'));
|
permission.get('documentMove') || permission.get('documentCopy') || permission.get('documentTemplate') ||
|
||||||
|
permission.get('documentApprove') || permission.get('documentLifecycle') || permission.get('documentVersion'));
|
||||||
});
|
});
|
||||||
|
|
||||||
// see if more than oen user is granted access to space (excluding everyone)
|
// see if more than oen user is granted access to space (excluding everyone)
|
||||||
|
@ -140,8 +143,9 @@ export default Component.extend(ModalMixin, {
|
||||||
permissions.forEach((permission) => {
|
permissions.forEach((permission) => {
|
||||||
if (permission.get('whoId') !== constants.EveryoneUserId &&
|
if (permission.get('whoId') !== constants.EveryoneUserId &&
|
||||||
(permission.get('spaceView') || permission.get('documentAdd') || permission.get('documentEdit') || permission.get('documentDelete') ||
|
(permission.get('spaceView') || permission.get('documentAdd') || permission.get('documentEdit') || permission.get('documentDelete') ||
|
||||||
permission.get('documentMove') || permission.get('documentCopy') || permission.get('documentTemplate') || permission.get('documentApprove'))) {
|
permission.get('documentMove') || permission.get('documentCopy') || permission.get('documentTemplate') ||
|
||||||
roleCount += 1;
|
permission.get('documentApprove') || permission.get('documentLifecycle') || permission.get('documentVersion'))) {
|
||||||
|
roleCount += 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -161,7 +165,7 @@ export default Component.extend(ModalMixin, {
|
||||||
},
|
},
|
||||||
|
|
||||||
onSearch() {
|
onSearch() {
|
||||||
debounce(this, function() {
|
debounce(this, function () {
|
||||||
let searchText = this.get('searchText').trim();
|
let searchText = this.get('searchText').trim();
|
||||||
|
|
||||||
if (searchText.length === 0) {
|
if (searchText.length === 0) {
|
||||||
|
@ -181,7 +185,6 @@ export default Component.extend(ModalMixin, {
|
||||||
if (is.undefined(exists)) {
|
if (is.undefined(exists)) {
|
||||||
spacePermissions.pushObject(this.permissionRecord(constants.WhoType.User, user.get('id'), user.get('fullname')));
|
spacePermissions.pushObject(this.permissionRecord(constants.WhoType.User, user.get('id'), user.get('fullname')));
|
||||||
this.set('spacePermissions', spacePermissions);
|
this.set('spacePermissions', spacePermissions);
|
||||||
// this.set('spacePermissions', spacePermissions.sortBy('who', 'name'));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ export default Model.extend({
|
||||||
documentCopy: attr('boolean'),
|
documentCopy: attr('boolean'),
|
||||||
documentTemplate: attr('boolean'),
|
documentTemplate: attr('boolean'),
|
||||||
documentApprove: attr('boolean'),
|
documentApprove: attr('boolean'),
|
||||||
|
documentLifecycle: attr('boolean'),
|
||||||
|
documentVersion: attr('boolean'),
|
||||||
name: attr('string'), // read-only
|
name: attr('string'), // read-only
|
||||||
members: attr('number') // read-only
|
members: attr('number') // read-only
|
||||||
});
|
});
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
<th class="text-info">Copy</th>
|
<th class="text-info">Copy</th>
|
||||||
<th class="text-info">Templates</th>
|
<th class="text-info">Templates</th>
|
||||||
<th class="text-info">Approval</th>
|
<th class="text-info">Approval</th>
|
||||||
|
<th class="text-info">Lifecycle</th>
|
||||||
|
<th class="text-info">Versions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -38,53 +40,35 @@
|
||||||
<small class="form-text text-muted d-inline-block">({{permission.members}})</small>
|
<small class="form-text text-muted d-inline-block">({{permission.members}})</small>
|
||||||
</span>
|
</span>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#if (eq permission.whoId constants.EveryoneUserId)}}
|
{{#if (eq permission.whoId constants.EveryoneUserId)}}
|
||||||
<span class="button-icon-green button-icon-small align-middle">
|
<span class="button-icon-green button-icon-small align-middle">
|
||||||
<i class="material-icons">language</i>
|
<i class="material-icons">language</i>
|
||||||
</span>
|
</span>
|
||||||
<span class="color-green"> {{permission.name}}</span>
|
<span class="color-green"> {{permission.name}}</span>
|
||||||
{{else}}
|
{{else}}
|
||||||
<span class="button-icon-gray button-icon-small align-middle">
|
<span class="button-icon-gray button-icon-small align-middle">
|
||||||
<i class="material-icons">person</i>
|
<i class="material-icons">person</i>
|
||||||
</span>
|
</span>
|
||||||
<span class=""> {{permission.name}}
|
<span class=""> {{permission.name}}
|
||||||
{{#if (eq permission.whoId session.user.id)}}
|
{{#if (eq permission.whoId session.user.id)}}
|
||||||
<small class="form-text text-muted d-inline-block">(you)</small>
|
<small class="form-text text-muted d-inline-block">(you)</small>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</span>
|
</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>{{input type="checkbox" id=(concat 'space-role-view-' permission.whoId) checked=permission.spaceView}}</td>
|
||||||
{{input type="checkbox" id=(concat 'space-role-view-' permission.whoId) checked=permission.spaceView}}
|
<td>{{input type="checkbox" id=(concat 'space-role-manage-' permission.whoId) checked=permission.spaceManage}}</td>
|
||||||
</td>
|
<td>{{input type="checkbox" id=(concat 'space-role-owner-' permission.whoId) checked=permission.spaceOwner}}</td>
|
||||||
<td>
|
<td>{{input type="checkbox" id=(concat 'doc-role-add-' permission.whoId) checked=permission.documentAdd}}</td>
|
||||||
{{input type="checkbox" id=(concat 'space-role-manage-' permission.whoId) checked=permission.spaceManage}}
|
<td>{{input type="checkbox" id=(concat 'doc-role-edit-' permission.whoId) checked=permission.documentEdit}}</td>
|
||||||
</td>
|
<td>{{input type="checkbox" id=(concat 'doc-role-delete-' permission.whoId) checked=permission.documentDelete}}</td>
|
||||||
<td>
|
<td>{{input type="checkbox" id=(concat 'doc-role-move-' permission.whoId) checked=permission.documentMove}}</td>
|
||||||
{{input type="checkbox" id=(concat 'space-role-owner-' permission.whoId) checked=permission.spaceOwner}}
|
<td>{{input type="checkbox" id=(concat 'doc-role-copy-' permission.whoId) checked=permission.documentCopy}}</td>
|
||||||
</td>
|
<td>{{input type="checkbox" id=(concat 'doc-role-template-' permission.whoId) checked=permission.documentTemplate}}</td>
|
||||||
<td>
|
<td>{{input type="checkbox" id=(concat 'doc-role-approve-' permission.whoId) checked=permission.documentApprove}}</td>
|
||||||
{{input type="checkbox" id=(concat 'doc-role-add-' permission.whoId) checked=permission.documentAdd}}
|
<td>{{input type="checkbox" id=(concat 'doc-role-lifecycle-' permission.whoId) checked=permission.documentLifecycle}}</td>
|
||||||
</td>
|
<td>{{input type="checkbox" id=(concat 'doc-role-version-' permission.whoId) checked=permission.documentVersion}}</td>
|
||||||
<td>
|
|
||||||
{{input type="checkbox" id=(concat 'doc-role-edit-' permission.whoId) checked=permission.documentEdit}}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{input type="checkbox" id=(concat 'doc-role-delete-' permission.whoId) checked=permission.documentDelete}}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{input type="checkbox" id=(concat 'doc-role-move-' permission.whoId) checked=permission.documentMove}}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{input type="checkbox" id=(concat 'doc-role-copy-' permission.whoId) checked=permission.documentCopy}}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{input type="checkbox" id=(concat 'doc-role-template-' permission.whoId) checked=permission.documentTemplate}}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{input type="checkbox" id=(concat 'doc-role-approve-' permission.whoId) checked=permission.documentApprove}}
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -113,7 +97,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">Cancel</button>
|
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">Cancel</button>
|
||||||
<button type="button" class="btn btn-success" onclick={{action 'setPermissions'}}>Save</button>
|
<button type="button" class="btn btn-success" onclick= {{action 'setPermissions'}}>Save</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "documize",
|
"name": "documize",
|
||||||
"version": "1.58.0",
|
"version": "1.59.0",
|
||||||
"description": "The Document IDE",
|
"description": "The Document IDE",
|
||||||
"private": true,
|
"private": true,
|
||||||
"repository": "",
|
"repository": "",
|
||||||
|
|
14
meta.json
14
meta.json
|
@ -1,16 +1,14 @@
|
||||||
{
|
{
|
||||||
"community":
|
"community": {
|
||||||
{
|
"version": "1.59.0",
|
||||||
"version": "1.58.0",
|
|
||||||
"major": 1,
|
"major": 1,
|
||||||
"minor": 58,
|
"minor": 59,
|
||||||
"patch": 0
|
"patch": 0
|
||||||
},
|
},
|
||||||
"enterprise":
|
"enterprise": {
|
||||||
{
|
"version": "1.61.0",
|
||||||
"version": "1.60.0",
|
|
||||||
"major": 1,
|
"major": 1,
|
||||||
"minor": 60,
|
"minor": 61,
|
||||||
"patch": 0
|
"patch": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -22,18 +22,23 @@ import (
|
||||||
// Document represents the purpose of Documize.
|
// Document represents the purpose of Documize.
|
||||||
type Document struct {
|
type Document struct {
|
||||||
model.BaseEntity
|
model.BaseEntity
|
||||||
OrgID string `json:"orgId"`
|
OrgID string `json:"orgId"`
|
||||||
LabelID string `json:"folderId"`
|
LabelID string `json:"folderId"`
|
||||||
UserID string `json:"userId"`
|
UserID string `json:"userId"`
|
||||||
Job string `json:"job"`
|
Job string `json:"job"`
|
||||||
Location string `json:"location"`
|
Location string `json:"location"`
|
||||||
Title string `json:"name"`
|
Title string `json:"name"`
|
||||||
Excerpt string `json:"excerpt"`
|
Excerpt string `json:"excerpt"`
|
||||||
Slug string `json:"-"`
|
Slug string `json:"-"`
|
||||||
Tags string `json:"tags"`
|
Tags string `json:"tags"`
|
||||||
Template bool `json:"template"`
|
Template bool `json:"template"`
|
||||||
Protection workflow.Protection `json:"protection"`
|
Protection workflow.Protection `json:"protection"`
|
||||||
Approval workflow.Approval `json:"approval"`
|
Approval workflow.Approval `json:"approval"`
|
||||||
|
Lifecycle workflow.Lifecycle `json:"lifecycle"`
|
||||||
|
Versioned bool `json:"versioned"`
|
||||||
|
VersionID string `json:"versionId"`
|
||||||
|
VersionOrder int `json:"versionOrder"`
|
||||||
|
GroupID string `json:"groupId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDefaults ensures on blanks and cleans.
|
// SetDefaults ensures on blanks and cleans.
|
||||||
|
|
|
@ -93,6 +93,12 @@ const (
|
||||||
// DocumentApprove means you can approve a change to a document
|
// DocumentApprove means you can approve a change to a document
|
||||||
DocumentApprove Action = "doc-approve"
|
DocumentApprove Action = "doc-approve"
|
||||||
|
|
||||||
|
// DocumentLifecycle means you can move a document between DRAFT/LIVE/ARCHIVE states
|
||||||
|
DocumentLifecycle Action = "doc-lifecycle"
|
||||||
|
|
||||||
|
// DocumentVersion means you can manage document versions
|
||||||
|
DocumentVersion Action = "doc-version"
|
||||||
|
|
||||||
// CategoryView action means you can view a category and documents therein
|
// CategoryView action means you can view a category and documents therein
|
||||||
CategoryView Action = "view"
|
CategoryView Action = "view"
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,21 +15,23 @@ package permission
|
||||||
// This data structure is made from database permission records for the space,
|
// This data structure is made from database permission records for the space,
|
||||||
// and it is designed to be sent to HTTP clients (web, mobile).
|
// and it is designed to be sent to HTTP clients (web, mobile).
|
||||||
type Record struct {
|
type Record struct {
|
||||||
OrgID string `json:"orgId"`
|
OrgID string `json:"orgId"`
|
||||||
SpaceID string `json:"folderId"`
|
SpaceID string `json:"folderId"`
|
||||||
WhoID string `json:"whoId"`
|
WhoID string `json:"whoId"`
|
||||||
Who WhoType `json:"who"`
|
Who WhoType `json:"who"`
|
||||||
SpaceView bool `json:"spaceView"`
|
SpaceView bool `json:"spaceView"`
|
||||||
SpaceManage bool `json:"spaceManage"`
|
SpaceManage bool `json:"spaceManage"`
|
||||||
SpaceOwner bool `json:"spaceOwner"`
|
SpaceOwner bool `json:"spaceOwner"`
|
||||||
DocumentAdd bool `json:"documentAdd"`
|
DocumentAdd bool `json:"documentAdd"`
|
||||||
DocumentEdit bool `json:"documentEdit"`
|
DocumentEdit bool `json:"documentEdit"`
|
||||||
DocumentDelete bool `json:"documentDelete"`
|
DocumentDelete bool `json:"documentDelete"`
|
||||||
DocumentMove bool `json:"documentMove"`
|
DocumentMove bool `json:"documentMove"`
|
||||||
DocumentCopy bool `json:"documentCopy"`
|
DocumentCopy bool `json:"documentCopy"`
|
||||||
DocumentTemplate bool `json:"documentTemplate"`
|
DocumentTemplate bool `json:"documentTemplate"`
|
||||||
DocumentApprove bool `json:"documentApprove"`
|
DocumentApprove bool `json:"documentApprove"`
|
||||||
Name string `json:"name"` // read-only, user or group name
|
DocumentLifecycle bool `json:"documentLifecycle"`
|
||||||
|
DocumentVersion bool `json:"documentVersion"`
|
||||||
|
Name string `json:"name"` // read-only, user or group name
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeUserPermissions returns a flat, usable permission summary record
|
// DecodeUserPermissions returns a flat, usable permission summary record
|
||||||
|
@ -67,6 +69,10 @@ func DecodeUserPermissions(perm []Permission) (r Record) {
|
||||||
r.DocumentTemplate = true
|
r.DocumentTemplate = true
|
||||||
case DocumentApprove:
|
case DocumentApprove:
|
||||||
r.DocumentApprove = true
|
r.DocumentApprove = true
|
||||||
|
case DocumentLifecycle:
|
||||||
|
r.DocumentLifecycle = true
|
||||||
|
case DocumentVersion:
|
||||||
|
r.DocumentVersion = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +113,12 @@ func EncodeUserPermissions(r Record) (perm []Permission) {
|
||||||
if r.DocumentApprove {
|
if r.DocumentApprove {
|
||||||
perm = append(perm, EncodeRecord(r, DocumentApprove))
|
perm = append(perm, EncodeRecord(r, DocumentApprove))
|
||||||
}
|
}
|
||||||
|
if r.DocumentVersion {
|
||||||
|
perm = append(perm, EncodeRecord(r, DocumentVersion))
|
||||||
|
}
|
||||||
|
if r.DocumentLifecycle {
|
||||||
|
perm = append(perm, EncodeRecord(r, DocumentLifecycle))
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -114,7 +126,8 @@ func EncodeUserPermissions(r Record) (perm []Permission) {
|
||||||
// HasAnyPermission returns true if user has at least one permission.
|
// HasAnyPermission returns true if user has at least one permission.
|
||||||
func HasAnyPermission(p Record) bool {
|
func HasAnyPermission(p Record) bool {
|
||||||
return p.SpaceView || p.SpaceManage || p.SpaceOwner || p.DocumentAdd || p.DocumentEdit ||
|
return p.SpaceView || p.SpaceManage || p.SpaceOwner || p.DocumentAdd || p.DocumentEdit ||
|
||||||
p.DocumentDelete || p.DocumentMove || p.DocumentCopy || p.DocumentTemplate || p.DocumentApprove
|
p.DocumentDelete || p.DocumentMove || p.DocumentCopy || p.DocumentTemplate || p.DocumentApprove ||
|
||||||
|
p.DocumentLifecycle || p.DocumentVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeRecord creates standard permission record representing user permissions for a space.
|
// EncodeRecord creates standard permission record representing user permissions for a space.
|
||||||
|
@ -138,7 +151,6 @@ type CategoryViewRequestModel struct {
|
||||||
CategoryID string `json:"categoryID"`
|
CategoryID string `json:"categoryID"`
|
||||||
WhoID string `json:"whoId"`
|
WhoID string `json:"whoId"`
|
||||||
Who WhoType `json:"who"`
|
Who WhoType `json:"who"`
|
||||||
// UserID string `json:"userId"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SpaceRequestModel details which users have what permissions on a given space.
|
// SpaceRequestModel details which users have what permissions on a given space.
|
||||||
|
|
|
@ -63,3 +63,17 @@ const (
|
||||||
// ChangePendingNew means a new section to a document is pending review
|
// ChangePendingNew means a new section to a document is pending review
|
||||||
ChangePendingNew ChangeStatus = 4
|
ChangePendingNew ChangeStatus = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Lifecycle tells us if document is in Draft, Live, Archived
|
||||||
|
type Lifecycle int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// LifecycleDraft means document is in draft mode with restricted viewing
|
||||||
|
LifecycleDraft Lifecycle = 0
|
||||||
|
|
||||||
|
// LifecycleLive means document can be seen by all
|
||||||
|
LifecycleLive Lifecycle = 1
|
||||||
|
|
||||||
|
// LifecycleArchived means document has been archived
|
||||||
|
LifecycleArchived Lifecycle = 2
|
||||||
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue