1
0
Fork 0
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:
Harvey Kandola 2018-03-14 13:38:37 +00:00
parent 4e32bffebe
commit 958f4d30b9
19 changed files with 918 additions and 782 deletions

View file

@ -52,7 +52,7 @@ Space view.
## Latest version ## Latest version
Community edition: v1.58.0 Community edition: v1.59.0
## OS support ## OS support

View file

@ -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)

View 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

View file

@ -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)
if d.Lifecycle == workflow.LifecycleLive {
go h.Indexer.IndexDocument(ctx, d, a) 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)
if d.Lifecycle == workflow.LifecycleLive {
go h.Indexer.IndexDocument(ctx, d, all) go h.Indexer.IndexDocument(ctx, d, all)
} else {
go h.Indexer.DeleteDocument(ctx, d.RefID)
}
response.WriteEmpty(w) response.WriteEmpty(w)
} }

View file

@ -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)
if d.Lifecycle == workflow.LifecycleLive {
go h.Indexer.IndexDocument(ctx, d, a) go h.Indexer.IndexDocument(ctx, d, a)
} else {
go h.Indexer.DeleteDocument(ctx, d.RefID)
}
response.WriteEmpty(w) response.WriteEmpty(w)
} }

View file

@ -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")
} }
@ -185,8 +203,13 @@ func (s Scope) PublicDocuments(ctx domain.RequestContext, orgID string) (documen
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.lifecycle=1
AND d.template=0`, orgID) 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 {

View file

@ -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)
if doc.Lifecycle == workflow.LifecycleLive {
go h.Indexer.IndexContent(ctx, np) 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()
if doc.Lifecycle == workflow.LifecycleLive {
go h.Indexer.IndexContent(ctx, model.Page) 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)

View file

@ -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)
if nd.Lifecycle == workflow.LifecycleLive {
go h.Indexer.IndexDocument(ctx, nd, a) go h.Indexer.IndexDocument(ctx, nd, a)
} else {
go h.Indexer.DeleteDocument(ctx, d.RefID)
}
response.WriteJSON(w, nd) response.WriteJSON(w, nd)
} }

View file

@ -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

View file

@ -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,7 +143,8 @@ 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') ||
permission.get('documentApprove') || permission.get('documentLifecycle') || permission.get('documentVersion'))) {
roleCount += 1; 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'));
} }
}, },
} }

View file

@ -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
}); });

View file

@ -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>
@ -55,36 +57,18 @@
{{/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>

View file

@ -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": "",

View file

@ -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
} }
} }

View file

@ -34,6 +34,11 @@ type Document struct {
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.

View file

@ -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"
) )

View file

@ -29,6 +29,8 @@ type Record struct {
DocumentCopy bool `json:"documentCopy"` DocumentCopy bool `json:"documentCopy"`
DocumentTemplate bool `json:"documentTemplate"` DocumentTemplate bool `json:"documentTemplate"`
DocumentApprove bool `json:"documentApprove"` DocumentApprove bool `json:"documentApprove"`
DocumentLifecycle bool `json:"documentLifecycle"`
DocumentVersion bool `json:"documentVersion"`
Name string `json:"name"` // read-only, user or group name Name string `json:"name"` // read-only, user or group name
} }
@ -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.

View file

@ -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
)