1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-19 13:19:43 +02:00

document approvals and protection

This commit is contained in:
Harvey Kandola 2017-12-24 15:51:43 +00:00
parent 58c88e2127
commit f4f32bcfcb
20 changed files with 891 additions and 777 deletions

View file

@ -171,7 +171,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"} perms := []string{"view", "manage", "own", "doc-add", "doc-edit", "doc-delete", "doc-move", "doc-copy", "doc-template", "doc-approve"}
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

@ -1,8 +1,7 @@
## TODO ## PENDING REMOVALS
1. Remove audit table NONE
2. Remove document.layout field ?
## MYSQL ENCODING ## MYSQL ENCODING

View file

@ -0,0 +1,14 @@
/* enterprise edition */
-- document needs proection and approval columns
ALTER TABLE document ADD COLUMN `protection` INT NOT NULL DEFAULT 0 AFTER `template`;
ALTER TABLE document ADD COLUMN `approval` INT NOT NULL DEFAULT 0 AFTER `protection`;
-- page needs proection and approval columns
ALTER TABLE page ADD COLUMN `protection` INT NOT NULL DEFAULT 0 AFTER `revisions`;
ALTER TABLE page ADD COLUMN `approval` INT NOT NULL DEFAULT 0 AFTER `protection`;
-- data migration clean up from previous releases
DROP TABLE IF EXISTS `audit`;
DROP TABLE IF EXISTS `search_old`;
ALTER TABLE document DROP COLUMN `layout`;

View file

@ -34,8 +34,8 @@ func (s Scope) Add(ctx domain.RequestContext, document doc.Document) (err error)
document.Created = time.Now().UTC() document.Created = time.Now().UTC()
document.Revised = document.Created // put same time in both fields document.Revised = document.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, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", _, 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.Created, document.Revised) 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)
if err != nil { if err != nil {
err = errors.Wrap(err, "execuet insert document") err = errors.Wrap(err, "execuet insert document")
@ -46,7 +46,7 @@ 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, layout, 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, created, revised FROM document WHERE orgid=? and refid=?",
ctx.OrgID, id) ctx.OrgID, id)
if err != nil { if err != nil {
@ -92,7 +92,7 @@ func (s Scope) DocumentMeta(ctx domain.RequestContext, id string) (meta doc.Docu
// GetAll returns a slice containg all of the the documents for the client's organisation, with the most recient first. // GetAll returns a slice containg all of the the documents for the client's organisation, with the most recient first.
func (s Scope) GetAll() (ctx domain.RequestContext, documents []doc.Document, err error) { func (s Scope) GetAll() (ctx domain.RequestContext, documents []doc.Document, err error) {
err = s.Runtime.Db.Select(&documents, "SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template, layout, created, revised FROM document WHERE orgid=? AND template=0 ORDER BY revised DESC", ctx.OrgID) err = s.Runtime.Db.Select(&documents, "SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template, protection, approval, created, revised FROM document WHERE orgid=? AND template=0 ORDER BY revised DESC", ctx.OrgID)
if err != nil { if err != nil {
err = errors.Wrap(err, "select documents") err = errors.Wrap(err, "select documents")
@ -106,7 +106,7 @@ 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, layout, created, revised SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template, protection, approval, 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
@ -128,7 +128,7 @@ 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, layout, created, revised FROM document WHERE orgid=? AND template=1 `SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template, protection, approval, created, revised FROM document WHERE orgid=? AND template=1
AND labelid IN AND labelid IN
( (
SELECT refid FROM label WHERE orgid=? SELECT refid FROM label WHERE orgid=?
@ -150,7 +150,7 @@ 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, layout, 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, created, revised FROM document WHERE orgid=? AND labelid=? AND template=1
AND labelid IN AND labelid IN
( (
SELECT refid FROM label WHERE orgid=? SELECT refid FROM label WHERE orgid=?
@ -193,7 +193,7 @@ 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, layout, created, revised FROM document WHERE orgid=? AND template=0 `SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template, protection, approval, created, revised FROM document WHERE orgid=? AND template=0
AND labelid IN AND labelid IN
( (
SELECT refid FROM label WHERE orgid=? SELECT refid FROM label WHERE orgid=?
@ -221,7 +221,7 @@ 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, layout=:layout, 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, revised=:revised WHERE orgid=:orgid AND refid=:refid",
&document) &document)
if err != nil { if err != nil {

View file

@ -54,8 +54,8 @@ func (s Scope) Add(ctx domain.RequestContext, model page.NewPage) (err error) {
model.Page.Sequence = maxSeq * 2 model.Page.Sequence = maxSeq * 2
} }
_, err = ctx.Transaction.Exec("INSERT INTO page (refid, orgid, documentid, userid, contenttype, pagetype, level, title, body, revisions, sequence, blockid, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", _, err = ctx.Transaction.Exec("INSERT INTO page (refid, orgid, documentid, userid, contenttype, pagetype, level, title, body, revisions, sequence, blockid, protected, approval, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
model.Page.RefID, model.Page.OrgID, model.Page.DocumentID, model.Page.UserID, model.Page.ContentType, model.Page.PageType, model.Page.Level, model.Page.Title, model.Page.Body, model.Page.Revisions, model.Page.Sequence, model.Page.BlockID, model.Page.Created, model.Page.Revised) model.Page.RefID, model.Page.OrgID, model.Page.DocumentID, model.Page.UserID, model.Page.ContentType, model.Page.PageType, model.Page.Level, model.Page.Title, model.Page.Body, model.Page.Revisions, model.Page.Sequence, model.Page.BlockID, model.Page.Protection, model.Page.Approval, model.Page.Created, model.Page.Revised)
_, err = ctx.Transaction.Exec("INSERT INTO pagemeta (pageid, orgid, userid, documentid, rawbody, config, externalsource, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", _, err = ctx.Transaction.Exec("INSERT INTO pagemeta (pageid, orgid, userid, documentid, rawbody, config, externalsource, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
model.Meta.PageID, model.Meta.OrgID, model.Meta.UserID, model.Meta.DocumentID, model.Meta.RawBody, model.Meta.Config, model.Meta.ExternalSource, model.Meta.Created, model.Meta.Revised) model.Meta.PageID, model.Meta.OrgID, model.Meta.UserID, model.Meta.DocumentID, model.Meta.RawBody, model.Meta.Config, model.Meta.ExternalSource, model.Meta.Created, model.Meta.Revised)
@ -69,7 +69,7 @@ func (s Scope) Add(ctx domain.RequestContext, model page.NewPage) (err error) {
// Get returns the pageID page record from the page table. // Get returns the pageID page record from the page table.
func (s Scope) Get(ctx domain.RequestContext, pageID string) (p page.Page, err error) { func (s Scope) Get(ctx domain.RequestContext, pageID string) (p page.Page, err error) {
err = s.Runtime.Db.Get(&p, "SELECT a.id, a.refid, a.orgid, a.documentid, a.userid, a.contenttype, a.pagetype, a.level, a.sequence, a.title, a.body, a.revisions, a.blockid, a.created, a.revised FROM page a WHERE a.orgid=? AND a.refid=?", err = s.Runtime.Db.Get(&p, "SELECT a.id, a.refid, a.orgid, a.documentid, a.userid, a.contenttype, a.pagetype, a.level, a.sequence, a.title, a.body, a.revisions, a.blockid, a.protection, a.approval, a.created, a.revised FROM page a WHERE a.orgid=? AND a.refid=?",
ctx.OrgID, pageID) ctx.OrgID, pageID)
if err != nil { if err != nil {
@ -81,7 +81,7 @@ func (s Scope) Get(ctx domain.RequestContext, pageID string) (p page.Page, err e
// GetPages returns a slice containing all the page records for a given documentID, in presentation sequence. // GetPages returns a slice containing all the page records for a given documentID, in presentation sequence.
func (s Scope) GetPages(ctx domain.RequestContext, documentID string) (p []page.Page, err error) { func (s Scope) GetPages(ctx domain.RequestContext, documentID string) (p []page.Page, err error) {
err = s.Runtime.Db.Select(&p, "SELECT a.id, a.refid, a.orgid, a.documentid, a.userid, a.contenttype, a.pagetype, a.level, a.sequence, a.title, a.body, a.revisions, a.blockid, a.created, a.revised FROM page a WHERE a.orgid=? AND a.documentid=? ORDER BY a.sequence", ctx.OrgID, documentID) err = s.Runtime.Db.Select(&p, "SELECT a.id, a.refid, a.orgid, a.documentid, a.userid, a.contenttype, a.pagetype, a.level, a.sequence, a.title, a.body, a.revisions, a.blockid, a.protection, a.approval, a.created, a.revised FROM page a WHERE a.orgid=? AND a.documentid=? ORDER BY a.sequence", ctx.OrgID, documentID)
if err != nil { if err != nil {
err = errors.Wrap(err, "execute get pages") err = errors.Wrap(err, "execute get pages")
@ -93,7 +93,7 @@ func (s Scope) GetPages(ctx domain.RequestContext, documentID string) (p []page.
// GetPagesWithoutContent returns a slice containing all the page records for a given documentID, in presentation sequence, // GetPagesWithoutContent returns a slice containing all the page records for a given documentID, in presentation sequence,
// but without the body field (which holds the HTML content). // but without the body field (which holds the HTML content).
func (s Scope) GetPagesWithoutContent(ctx domain.RequestContext, documentID string) (pages []page.Page, err error) { func (s Scope) GetPagesWithoutContent(ctx domain.RequestContext, documentID string) (pages []page.Page, err error) {
err = s.Runtime.Db.Select(&pages, "SELECT id, refid, orgid, documentid, userid, contenttype, pagetype, sequence, level, title, revisions, blockid, created, revised FROM page WHERE orgid=? AND documentid=? ORDER BY sequence", ctx.OrgID, documentID) err = s.Runtime.Db.Select(&pages, "SELECT id, refid, orgid, documentid, userid, contenttype, pagetype, sequence, level, title, revisions, blockid, protection, approval, created, revised FROM page WHERE orgid=? AND documentid=? ORDER BY sequence", ctx.OrgID, documentID)
if err != nil { if err != nil {
err = errors.Wrap(err, fmt.Sprintf("Unable to execute select pages for org %s and document %s", ctx.OrgID, documentID)) err = errors.Wrap(err, fmt.Sprintf("Unable to execute select pages for org %s and document %s", ctx.OrgID, documentID))
@ -119,7 +119,7 @@ func (s Scope) Update(ctx domain.RequestContext, page page.Page, refID, userID s
} }
// Update page // Update page
_, err = ctx.Transaction.NamedExec("UPDATE page SET documentid=:documentid, level=:level, title=:title, body=:body, revisions=:revisions, sequence=:sequence, revised=:revised WHERE orgid=:orgid AND refid=:refid", _, err = ctx.Transaction.NamedExec("UPDATE page SET documentid=:documentid, level=:level, title=:title, body=:body, revisions=:revisions, sequence=:sequence, protection=:protection, approval=:approval, revised=:revised WHERE orgid=:orgid AND refid=:refid",
&page) &page)
if err != nil { if err != nil {

File diff suppressed because one or more lines are too long

View file

@ -139,7 +139,7 @@ export default Component.extend({
}); });
} else { } else {
if (data.authProvider === this.get('appMeta.authProvider')) { if (data.authProvider === this.get('appMeta.authProvider')) {
// this.showNotification(response.message); this.showNotification(response.message);
} else { } else {
this.get('onChange')(data); this.get('onChange')(data);
} }

View file

@ -10,12 +10,10 @@
// https://documize.com // https://documize.com
import { setProperties } from '@ember/object'; import { setProperties } from '@ember/object';
import Component from '@ember/component'; import Component from '@ember/component';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import NotifierMixin from '../../mixins/notifier';
export default Component.extend(NotifierMixin, { export default Component.extend({
folderService: service('folder'), folderService: service('folder'),
userService: service('user'), userService: service('user'),
appMeta: service(), appMeta: service(),
@ -42,7 +40,8 @@ export default Component.extend(NotifierMixin, {
documentDelete: false, documentDelete: false,
documentMove: false, documentMove: false,
documentCopy: false, documentCopy: false,
documentTemplate: false documentTemplate: false,
documentApprove: false,
}; };
let data = this.get('store').normalize('space-permission', u) let data = this.get('store').normalize('space-permission', u)
@ -63,8 +62,9 @@ export default Component.extend(NotifierMixin, {
documentDelete: false, documentDelete: false,
documentMove: false, documentMove: false,
documentCopy: false, documentCopy: false,
documentTemplate: false documentTemplate: false,
}; documentApprove: false,
};
let data = this.get('store').normalize('space-permission', u) let data = this.get('store').normalize('space-permission', u)
folderPermissions.pushObject(this.get('store').push(data)); folderPermissions.pushObject(this.get('store').push(data));
@ -96,7 +96,7 @@ export default Component.extend(NotifierMixin, {
let hasEveryone = _.find(permissions, function (permission) { let hasEveryone = _.find(permissions, function (permission) {
return permission.get('userId') === "0" && return permission.get('userId') === "0" &&
(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('documentMove') || permission.get('documentCopy') || permission.get('documentTemplate') || permission.get('documentApprove'));
}); });
// 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)
@ -104,26 +104,22 @@ export default Component.extend(NotifierMixin, {
permissions.forEach((permission) => { permissions.forEach((permission) => {
if (permission.get('userId') !== "0" && if (permission.get('userId') !== "0" &&
(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('documentMove') || permission.get('documentCopy') || permission.get('documentTemplate') || permission.get('documentApprove'))) {
roleCount += 1; roleCount += 1;
} }
}); });
if (is.not.undefined(hasEveryone)) { if (is.not.undefined(hasEveryone)) {
folder.markAsPublic(); folder.markAsPublic();
this.showNotification('Marked space as public');
} else { } else {
if (roleCount > 1) { if (roleCount > 1) {
folder.markAsRestricted(); folder.markAsRestricted();
this.showNotification('Marked space as protected');
} else { } else {
folder.markAsPrivate(); folder.markAsPrivate();
this.showNotification('Marked space as private');
} }
} }
this.get('folderService').savePermissions(folder.get('id'), payload).then(() => { this.get('folderService').savePermissions(folder.get('id'), payload).then(() => {
this.showNotification('Saved permissions');
$('#space-permission-modal').modal('hide'); $('#space-permission-modal').modal('hide');
$('#space-permission-modal').modal('dispose'); $('#space-permission-modal').modal('dispose');
}); });

View file

@ -10,7 +10,6 @@
// https://documize.com // https://documize.com
import { run } from '@ember/runloop'; import { run } from '@ember/runloop';
import Component from '@ember/component'; import Component from '@ember/component';
import miscUtil from '../utils/misc'; import miscUtil from '../utils/misc';

View file

@ -25,7 +25,8 @@ export default Model.extend({
userId: attr('string'), userId: attr('string'),
tags: attr('string'), tags: attr('string'),
template: attr('boolean'), template: attr('boolean'),
layout: attr('string'), protection: attr('number', { defaultValue: 0 }),
approval: attr('number', { defaultValue: 0 }),
// client-side property // client-side property
selected: attr('boolean', { defaultValue: false }), selected: attr('boolean', { defaultValue: false }),

View file

@ -28,7 +28,9 @@ export default Model.extend({
body: attr('string'), body: attr('string'),
rawBody: attr('string'), rawBody: attr('string'),
meta: attr(), meta: attr(),
protection: attr('number', { defaultValue: 0 }),
approval: attr('number', { defaultValue: 0 }),
tagName: computed('level', function () { tagName: computed('level', function () {
return "h2"; return "h2";
// return "h" + (this.get('level') + 1); // return "h" + (this.get('level') + 1);

View file

@ -27,5 +27,6 @@ export default Model.extend({
documentDelete: attr('boolean'), documentDelete: attr('boolean'),
documentMove: attr('boolean'), documentMove: attr('boolean'),
documentCopy: attr('boolean'), documentCopy: attr('boolean'),
documentTemplate: attr('boolean') documentTemplate: attr('boolean'),
documentApprove: attr('boolean')
}); });

View file

@ -10,7 +10,6 @@
// https://documize.com // https://documize.com
import Controller from '@ember/controller'; import Controller from '@ember/controller';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import NotifierMixin from '../../../mixins/notifier'; import NotifierMixin from '../../../mixins/notifier';
@ -24,8 +23,6 @@ export default Controller.extend(NotifierMixin, {
actions: { actions: {
onAddSpace(payload) { onAddSpace(payload) {
let self = this; let self = this;
this.showNotification("Added");
this.get('folderService').add(payload).then(function (newFolder) { this.get('folderService').add(payload).then(function (newFolder) {
self.get('folderService').setCurrentFolder(newFolder); self.get('folderService').setCurrentFolder(newFolder);
self.transitionToRoute('folder', newFolder.get('id'), newFolder.get('slug')); self.transitionToRoute('folder', newFolder.get('id'), newFolder.get('slug'));
@ -34,7 +31,6 @@ export default Controller.extend(NotifierMixin, {
onDeleteSpace(id) { onDeleteSpace(id) {
this.get('folderService').delete(id).then(() => { /* jshint ignore:line */ this.get('folderService').delete(id).then(() => { /* jshint ignore:line */
this.showNotification("Deleted");
this.get('localStorage').clearSessionItem('folder'); this.get('localStorage').clearSessionItem('folder');
this.transitionToRoute('folders'); this.transitionToRoute('folders');
}); });

View file

@ -10,7 +10,7 @@
<tr> <tr>
<th></th> <th></th>
<th colspan="3">Spaces</th> <th colspan="3">Spaces</th>
<th colspan="6" class="text-info">Documents</th> <th colspan="7" class="text-info">Documents</th>
</tr> </tr>
<tr> <tr>
<th></th> <th></th>
@ -23,6 +23,7 @@
<th class="text-info">Move</th> <th class="text-info">Move</th>
<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>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -56,6 +57,9 @@
<td> <td>
{{input type="checkbox" id=(concat 'doc-role-template-' permission.userId) checked=permission.documentTemplate}} {{input type="checkbox" id=(concat 'doc-role-template-' permission.userId) checked=permission.documentTemplate}}
</td> </td>
<td>
{{input type="checkbox" id=(concat 'doc-role-approve-' permission.userId) checked=permission.documentApprove}}
</td>
</tr> </tr>
{{/each}} {{/each}}
</tbody> </tbody>

View file

@ -39,5 +39,18 @@ export default {
PublishedTemplate: 8, PublishedTemplate: 8,
PublishedBlock: 9, PublishedBlock: 9,
Feedback: 10 Feedback: 10
},
ProtectionType: {
None: 0,
Lock: 1,
Review: 2
},
ApprovalType: {
None: 0,
Anybody: 1,
Majority: 2,
Unanimous: 3
} }
}; };

View file

@ -10,9 +10,7 @@
// https://documize.com // https://documize.com
import { htmlSafe } from '@ember/string'; import { htmlSafe } from '@ember/string';
import EmberObject, { computed } from '@ember/object'; import EmberObject, { computed } from '@ember/object';
import Ember from 'ember'; import Ember from 'ember';
import stringUtil from '../utils/string'; import stringUtil from '../utils/string';
import constants from '../utils/constants'; import constants from '../utils/constants';
@ -98,6 +96,8 @@ let DocumentModel = BaseModel.extend({
userId: "", userId: "",
tags: "", tags: "",
template: "", template: "",
protection: constants.ProtectionType.None,
approval: constants.ApprovalType.None,
slug: computed('name', function () { slug: computed('name', function () {
return stringUtil.makeSlug(this.get('name')); return stringUtil.makeSlug(this.get('name'));
@ -164,6 +164,8 @@ let PageModel = BaseModel.extend({
title: "", title: "",
body: "", body: "",
rawBody: "", rawBody: "",
protection: constants.ProtectionType.None,
approval: constants.ApprovalType.None,
meta: {}, meta: {},
tagName: computed('level', function () { tagName: computed('level', function () {
@ -202,7 +204,6 @@ let SectionModel = BaseModel.extend({
}); });
export default { export default {
TemplateModel,
AttachmentModel, AttachmentModel,
DocumentModel, DocumentModel,
FolderModel, FolderModel,
@ -210,6 +211,7 @@ export default {
PageModel, PageModel,
PageMetaModel, PageMetaModel,
ProtectedFolderParticipant, ProtectedFolderParticipant,
UserModel, SectionModel,
SectionModel TemplateModel,
UserModel
}; };

View file

@ -16,22 +16,24 @@ import (
"time" "time"
"github.com/documize/community/model" "github.com/documize/community/model"
"github.com/documize/community/model/workflow"
) )
// 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"`
Layout string `json:"layout"` Protection workflow.Protection `json:"protection"`
Approval workflow.Approval `json:"approval"`
} }
// SetDefaults ensures on blanks and cleans. // SetDefaults ensures on blanks and cleans.

View file

@ -16,23 +16,26 @@ import (
"time" "time"
"github.com/documize/community/model" "github.com/documize/community/model"
"github.com/documize/community/model/workflow"
) )
// Page represents a section within a document. // Page represents a section within a document.
type Page struct { type Page struct {
model.BaseEntity model.BaseEntity
OrgID string `json:"orgId"` OrgID string `json:"orgId"`
DocumentID string `json:"documentId"` DocumentID string `json:"documentId"`
UserID string `json:"userId"` UserID string `json:"userId"`
ContentType string `json:"contentType"` ContentType string `json:"contentType"`
PageType string `json:"pageType"` PageType string `json:"pageType"`
BlockID string `json:"blockId"` BlockID string `json:"blockId"`
Level uint64 `json:"level"` Level uint64 `json:"level"`
Sequence float64 `json:"sequence"` Sequence float64 `json:"sequence"`
Numbering string `json:"numbering"` Numbering string `json:"numbering"`
Title string `json:"title"` Title string `json:"title"`
Body string `json:"body"` Body string `json:"body"`
Revisions uint64 `json:"revisions"` Revisions uint64 `json:"revisions"`
Protection workflow.Protection `json:"protection"`
Approval workflow.Approval `json:"approval"`
} }
// SetDefaults ensures no blank values. // SetDefaults ensures no blank values.

View file

@ -32,24 +32,34 @@ type Action string
const ( const (
// SpaceView action means you can view a space and documents therein // SpaceView action means you can view a space and documents therein
SpaceView Action = "view" SpaceView Action = "view"
// SpaceManage action means you can add, remove users, set permissions, but not delete that space // SpaceManage action means you can add, remove users, set permissions, but not delete that space
SpaceManage Action = "manage" SpaceManage Action = "manage"
// SpaceOwner action means you can delete a space and do all SpaceManage functions // SpaceOwner action means you can delete a space and do all SpaceManage functions
SpaceOwner Action = "own" SpaceOwner Action = "own"
// DocumentAdd action means you can create/upload documents to a space // DocumentAdd action means you can create/upload documents to a space
DocumentAdd Action = "doc-add" DocumentAdd Action = "doc-add"
// DocumentEdit action means you can edit documents in a space // DocumentEdit action means you can edit documents in a space
DocumentEdit Action = "doc-edit" DocumentEdit Action = "doc-edit"
// DocumentDelete means you can delete documents in a space // DocumentDelete means you can delete documents in a space
DocumentDelete Action = "doc-delete" DocumentDelete Action = "doc-delete"
// DocumentMove means you can move documents between spaces // DocumentMove means you can move documents between spaces
DocumentMove Action = "doc-move" DocumentMove Action = "doc-move"
// DocumentCopy means you can copy documents within and between spaces // DocumentCopy means you can copy documents within and between spaces
DocumentCopy Action = "doc-copy" DocumentCopy Action = "doc-copy"
// DocumentTemplate means you can create, edit and delete document templates and content blocks // DocumentTemplate means you can create, edit and delete document templates and content blocks
DocumentTemplate Action = "doc-template" DocumentTemplate Action = "doc-template"
// DocumentApprove means you can approve a change to a document
DocumentApprove Action = "doc-approve"
// 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"
) )
@ -70,6 +80,7 @@ type Record struct {
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"`
} }
// DecodeUserPermissions returns a flat, usable permission summary record // DecodeUserPermissions returns a flat, usable permission summary record
@ -104,6 +115,8 @@ func DecodeUserPermissions(perm []Permission) (r Record) {
r.DocumentCopy = true r.DocumentCopy = true
case DocumentTemplate: case DocumentTemplate:
r.DocumentTemplate = true r.DocumentTemplate = true
case DocumentApprove:
r.DocumentApprove = true
} }
} }
@ -158,6 +171,9 @@ func EncodeUserPermissions(r Record) (perm []Permission) {
if r.DocumentTemplate { if r.DocumentTemplate {
perm = append(perm, EncodeRecord(r, DocumentTemplate)) perm = append(perm, EncodeRecord(r, DocumentTemplate))
} }
if r.DocumentApprove {
perm = append(perm, EncodeRecord(r, DocumentApprove))
}
return return
} }
@ -165,7 +181,7 @@ 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.DocumentDelete || p.DocumentMove || p.DocumentCopy || p.DocumentTemplate || p.DocumentApprove
} }
// EncodeRecord creates standard permission record representing user permissions for a space. // EncodeRecord creates standard permission record representing user permissions for a space.

View file

@ -0,0 +1,43 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
package workflow
// Protection tell us how to handle data item changes
type Protection int
const (
// NoProtection means no protection so data item changes are permitted
NoProtection Protection = 0
// Lock means no data itme changes
Lock Protection = 1
// Review means changes must be reviewed and approved
Review Protection = 2
)
// Approval tells us how some data item change is to be approved
type Approval int
const (
// NoApproval means no approval necessary
NoApproval Approval = 0
// Anybody can approve data item change
Anybody Approval = 1
// Majority must approve data item change
Majority Approval = 2
// Unanimous approval must be given for data item change
Unanimous Approval = 3
)