1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-18 20:59:43 +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

@ -25,7 +25,7 @@ Anyone who wants a single place for any kind of document.
Anyone who wants to loop in external participants complete security.
Anyone who wishes documentation and knowledge capture worked like agile software development.
## What's different about Documize?
Sane organization through personal, team and public spaces.
@ -52,7 +52,7 @@ Space view.
## Latest version
Community edition: v1.58.0
Community edition: v1.59.0
## OS support

View file

@ -170,7 +170,7 @@ func setupAccount(rt *env.Runtime, completion onboardRequest, serial string) (er
}
// 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 {
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)

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"
"github.com/documize/community/model/attachment"
"github.com/documize/community/model/audit"
"github.com/documize/community/model/workflow"
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)
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)
}
@ -236,7 +242,12 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
all, _ := h.Store.Attachment.GetAttachments(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)
}

View file

@ -249,7 +249,12 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
h.Store.Audit.Record(ctx, audit.EventTypeDocumentUpdate)
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)
}

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.
func (s Scope) Add(ctx domain.RequestContext, document doc.Document) (err error) {
document.OrgID = ctx.OrgID
document.Created = time.Now().UTC()
document.Revised = document.Created // put same time in both fields
func (s Scope) Add(ctx domain.RequestContext, d doc.Document) (err error) {
d.OrgID = ctx.OrgID
d.Created = time.Now().UTC()
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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
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)
_, err = ctx.Transaction.Exec(`
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 {
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.
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)
if err != nil {
@ -106,21 +113,23 @@ func (s Scope) GetAll() (ctx domain.RequestContext, documents []doc.Document, er
// by category permissions -- caller must filter as required.
func (s Scope) GetBySpace(ctx domain.RequestContext, spaceID string) (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
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 labelid IN (
SELECT refid FROM label WHERE orgid=? AND refid IN
SELECT refid FROM label WHERE orgid=? AND refid IN
(SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid=? AND refid IN (
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' AND action='view'
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=?
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.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)
if err == sql.ErrNoRows {
if err == sql.ErrNoRows || len(documents) == 0 {
err = nil
documents = []doc.Document{}
}
if err != nil {
err = errors.Wrap(err, "select documents by space")
@ -132,18 +141,25 @@ 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.
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, 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
(
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'
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")
}
@ -154,12 +170,15 @@ func (s Scope) Templates(ctx domain.RequestContext) (documents []doc.Document, e
// 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) {
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
(
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'
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')
))
@ -170,7 +189,6 @@ func (s Scope) TemplatesBySpace(ctx domain.RequestContext, spaceID string) (docu
err = nil
documents = []doc.Document{}
}
if err != nil {
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
FROM document d LEFT JOIN label l ON l.refid=d.labelid
WHERE d.orgid=?
AND l.type=1
AND d.template=0`, orgID)
AND l.type=1
AND d.lifecycle=1
AND d.template=0`, orgID)
if err == sql.ErrNoRows {
err = nil
documents = []doc.SitemapDocument{}
}
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("execute GetPublicDocuments for org %s%s", orgID))
}
@ -197,12 +220,15 @@ 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.
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, 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
(
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'
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')
))
@ -213,7 +239,6 @@ func (s Scope) DocumentList(ctx domain.RequestContext) (documents []doc.Document
err = nil
documents = []doc.Document{}
}
if err != nil {
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) {
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)
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)
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)
}
@ -309,6 +314,7 @@ func (h *Handler) GetMeta(w http.ResponseWriter, r *http.Request) {
// Update will persist changed page and note the fact
// that this is a new revision. If the page is the first in a document
// 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) {
method := "page.update"
ctx := domain.GetRequestContext(r)
@ -406,6 +412,11 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
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)
if err != nil {
ctx.Transaction.Rollback()
@ -470,7 +481,11 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
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)

View file

@ -35,6 +35,7 @@ import (
"github.com/documize/community/model/page"
pm "github.com/documize/community/model/permission"
"github.com/documize/community/model/template"
"github.com/documize/community/model/workflow"
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)
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)
}

View file

@ -41,7 +41,7 @@ func main() {
// product details
rt.Product = env.ProdInfo{}
rt.Product.Major = "1"
rt.Product.Minor = "58"
rt.Product.Minor = "59"
rt.Product.Patch = "0"
rt.Product.Version = fmt.Sprintf("%s.%s.%s", rt.Product.Major, rt.Product.Minor, rt.Product.Patch)
rt.Product.Edition = "Community"

File diff suppressed because one or more lines are too long

View file

@ -19,12 +19,12 @@ export default Component.extend(ModalMixin, {
groupSvc: service('group'),
spaceSvc: service('folder'),
userSvc: service('user'),
appMeta: service(),
appMeta: service(),
store: service(),
spacePermissions: null,
users: null,
searchText: '',
didReceiveAttrs() {
let spacePermissions = A([]);
let constants = this.get('constants');
@ -65,7 +65,7 @@ export default Component.extend(ModalMixin, {
// always show everyone
if (!hasEveryoneId) {
let pr = this.permissionRecord(constants.WhoType.User, constants.EveryoneUserId, ' ' + constants.EveryoneUserName);
spacePermissions.pushObject(pr);
spacePermissions.pushObject(pr);
}
this.set('spacePermissions', spacePermissions.sortBy('who', 'name'));
@ -93,6 +93,8 @@ export default Component.extend(ModalMixin, {
documentCopy: false,
documentTemplate: false,
documentApprove: false,
documentLifecycle: false,
documentVersion: false,
};
let rec = this.get('store').normalize('space-permission', raw);
@ -132,7 +134,8 @@ export default Component.extend(ModalMixin, {
let hasEveryone = _.find(permissions, (permission) => {
return permission.get('whoId') === constants.EveryoneUserId &&
(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)
@ -140,8 +143,9 @@ export default Component.extend(ModalMixin, {
permissions.forEach((permission) => {
if (permission.get('whoId') !== constants.EveryoneUserId &&
(permission.get('spaceView') || permission.get('documentAdd') || permission.get('documentEdit') || permission.get('documentDelete') ||
permission.get('documentMove') || permission.get('documentCopy') || permission.get('documentTemplate') || permission.get('documentApprove'))) {
roleCount += 1;
permission.get('documentMove') || permission.get('documentCopy') || permission.get('documentTemplate') ||
permission.get('documentApprove') || permission.get('documentLifecycle') || permission.get('documentVersion'))) {
roleCount += 1;
}
});
@ -161,7 +165,7 @@ export default Component.extend(ModalMixin, {
},
onSearch() {
debounce(this, function() {
debounce(this, function () {
let searchText = this.get('searchText').trim();
if (searchText.length === 0) {
@ -181,7 +185,6 @@ export default Component.extend(ModalMixin, {
if (is.undefined(exists)) {
spacePermissions.pushObject(this.permissionRecord(constants.WhoType.User, user.get('id'), user.get('fullname')));
this.set('spacePermissions', spacePermissions);
// this.set('spacePermissions', spacePermissions.sortBy('who', 'name'));
}
},
}

View file

@ -27,6 +27,8 @@ export default Model.extend({
documentCopy: attr('boolean'),
documentTemplate: attr('boolean'),
documentApprove: attr('boolean'),
documentLifecycle: attr('boolean'),
documentVersion: attr('boolean'),
name: attr('string'), // read-only
members: attr('number') // read-only
});

View file

@ -4,7 +4,7 @@
<div class="modal-header">Space Permissions</div>
<div class="modal-body" style="overflow-x: auto;">
<div class="space-admin table-responsive">
<table class="table table-hover permission-table mb-3">
<thead>
<tr>
@ -24,6 +24,8 @@
<th class="text-info">Copy</th>
<th class="text-info">Templates</th>
<th class="text-info">Approval</th>
<th class="text-info">Lifecycle</th>
<th class="text-info">Versions</th>
</tr>
</thead>
<tbody>
@ -38,53 +40,35 @@
<small class="form-text text-muted d-inline-block">({{permission.members}})</small>
</span>
{{else}}
{{#if (eq permission.whoId constants.EveryoneUserId)}}
<span class="button-icon-green button-icon-small align-middle">
<i class="material-icons">language</i>
</span>
<span class="color-green">&nbsp;{{permission.name}}</span>
{{else}}
<span class="button-icon-gray button-icon-small align-middle">
<i class="material-icons">person</i>
</span>
<span class="">&nbsp;{{permission.name}}
{{#if (eq permission.whoId session.user.id)}}
<small class="form-text text-muted d-inline-block">(you)</small>
{{/if}}
</span>
{{/if}}
{{#if (eq permission.whoId constants.EveryoneUserId)}}
<span class="button-icon-green button-icon-small align-middle">
<i class="material-icons">language</i>
</span>
<span class="color-green">&nbsp;{{permission.name}}</span>
{{else}}
<span class="button-icon-gray button-icon-small align-middle">
<i class="material-icons">person</i>
</span>
<span class="">&nbsp;{{permission.name}}
{{#if (eq permission.whoId session.user.id)}}
<small class="form-text text-muted d-inline-block">(you)</small>
{{/if}}
</span>
{{/if}}
{{/if}}
</td>
<td>
{{input type="checkbox" id=(concat 'space-role-view-' permission.whoId) checked=permission.spaceView}}
</td>
<td>
{{input type="checkbox" id=(concat 'space-role-manage-' permission.whoId) checked=permission.spaceManage}}
</td>
<td>
{{input type="checkbox" id=(concat 'space-role-owner-' permission.whoId) checked=permission.spaceOwner}}
</td>
<td>
{{input type="checkbox" id=(concat 'doc-role-add-' permission.whoId) checked=permission.documentAdd}}
</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>
<td>{{input type="checkbox" id=(concat 'space-role-view-' permission.whoId) checked=permission.spaceView}}</td>
<td>{{input type="checkbox" id=(concat 'space-role-manage-' permission.whoId) checked=permission.spaceManage}}</td>
<td>{{input type="checkbox" id=(concat 'space-role-owner-' permission.whoId) checked=permission.spaceOwner}}</td>
<td>{{input type="checkbox" id=(concat 'doc-role-add-' permission.whoId) checked=permission.documentAdd}}</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>
<td>{{input type="checkbox" id=(concat 'doc-role-lifecycle-' permission.whoId) checked=permission.documentLifecycle}}</td>
<td>{{input type="checkbox" id=(concat 'doc-role-version-' permission.whoId) checked=permission.documentVersion}}</td>
</tr>
{{/each}}
</tbody>
@ -108,13 +92,13 @@
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<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>

View file

@ -1,6 +1,6 @@
{
"name": "documize",
"version": "1.58.0",
"version": "1.59.0",
"description": "The Document IDE",
"private": true,
"repository": "",

View file

@ -1,16 +1,14 @@
{
"community":
{
"version": "1.58.0",
"community": {
"version": "1.59.0",
"major": 1,
"minor": 58,
"minor": 59,
"patch": 0
},
"enterprise":
{
"version": "1.60.0",
"enterprise": {
"version": "1.61.0",
"major": 1,
"minor": 60,
"minor": 61,
"patch": 0
}
}
}

View file

@ -22,18 +22,23 @@ import (
// Document represents the purpose of Documize.
type Document struct {
model.BaseEntity
OrgID string `json:"orgId"`
LabelID string `json:"folderId"`
UserID string `json:"userId"`
Job string `json:"job"`
Location string `json:"location"`
Title string `json:"name"`
Excerpt string `json:"excerpt"`
Slug string `json:"-"`
Tags string `json:"tags"`
Template bool `json:"template"`
Protection workflow.Protection `json:"protection"`
Approval workflow.Approval `json:"approval"`
OrgID string `json:"orgId"`
LabelID string `json:"folderId"`
UserID string `json:"userId"`
Job string `json:"job"`
Location string `json:"location"`
Title string `json:"name"`
Excerpt string `json:"excerpt"`
Slug string `json:"-"`
Tags string `json:"tags"`
Template bool `json:"template"`
Protection workflow.Protection `json:"protection"`
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.

View file

@ -93,6 +93,12 @@ const (
// DocumentApprove means you can approve a change to a document
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 = "view"
)

View file

@ -15,21 +15,23 @@ package permission
// This data structure is made from database permission records for the space,
// and it is designed to be sent to HTTP clients (web, mobile).
type Record struct {
OrgID string `json:"orgId"`
SpaceID string `json:"folderId"`
WhoID string `json:"whoId"`
Who WhoType `json:"who"`
SpaceView bool `json:"spaceView"`
SpaceManage bool `json:"spaceManage"`
SpaceOwner bool `json:"spaceOwner"`
DocumentAdd bool `json:"documentAdd"`
DocumentEdit bool `json:"documentEdit"`
DocumentDelete bool `json:"documentDelete"`
DocumentMove bool `json:"documentMove"`
DocumentCopy bool `json:"documentCopy"`
DocumentTemplate bool `json:"documentTemplate"`
DocumentApprove bool `json:"documentApprove"`
Name string `json:"name"` // read-only, user or group name
OrgID string `json:"orgId"`
SpaceID string `json:"folderId"`
WhoID string `json:"whoId"`
Who WhoType `json:"who"`
SpaceView bool `json:"spaceView"`
SpaceManage bool `json:"spaceManage"`
SpaceOwner bool `json:"spaceOwner"`
DocumentAdd bool `json:"documentAdd"`
DocumentEdit bool `json:"documentEdit"`
DocumentDelete bool `json:"documentDelete"`
DocumentMove bool `json:"documentMove"`
DocumentCopy bool `json:"documentCopy"`
DocumentTemplate bool `json:"documentTemplate"`
DocumentApprove bool `json:"documentApprove"`
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
@ -67,6 +69,10 @@ func DecodeUserPermissions(perm []Permission) (r Record) {
r.DocumentTemplate = true
case DocumentApprove:
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 {
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
}
@ -114,7 +126,8 @@ func EncodeUserPermissions(r Record) (perm []Permission) {
// HasAnyPermission returns true if user has at least one permission.
func HasAnyPermission(p Record) bool {
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.
@ -138,7 +151,6 @@ type CategoryViewRequestModel struct {
CategoryID string `json:"categoryID"`
WhoID string `json:"whoId"`
Who WhoType `json:"who"`
// UserID string `json:"userId"`
}
// 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 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
)