From 300b61758360e588ab0349973129aa6f444c67c9 Mon Sep 17 00:00:00 2001 From: Harvey Kandola Date: Mon, 18 Sep 2017 13:02:15 +0100 Subject: [PATCH] using all new permissions for securing spaces and documents WIP --- domain/document/endpoint.go | 12 +- domain/document/mysql/store.go | 100 ++--- domain/link/mysql/store.go | 76 ++-- domain/search/mysql/store.go | 36 +- domain/storer.go | 2 +- domain/user/mysql/store.go | 16 +- gui/app/components/document/document-page.js | 2 +- gui/app/components/document/page-heading.js | 9 +- .../components/document/sidebar-view-index.js | 10 +- gui/app/components/document/tab-heading.js | 7 + gui/app/components/document/tag-editor.js | 1 - gui/app/components/folder/folder-toolbar.js | 51 ++- gui/app/components/folder/sidebar-zone.js | 63 --- gui/app/pods/customize/route.js | 6 +- gui/app/pods/customize/template.hbs | 2 - gui/app/pods/document/block/template.hbs | 2 +- gui/app/pods/document/history/template.hbs | 2 +- gui/app/pods/document/index/route.js | 2 +- gui/app/pods/folder/index/route.js | 1 - gui/app/pods/folder/route.js | 2 +- .../folder/settings/invitation/controller.js | 15 + .../pods/folder/settings/invitation/route.js | 25 ++ .../folder/settings/invitation/template.hbs | 1 + gui/app/pods/folder/settings/route.js | 6 + .../folder/settings/security/controller.js | 15 + .../pods/folder/settings/security/route.js | 25 ++ .../folder/settings/security/template.hbs | 1 + gui/app/pods/folder/settings/template.hbs | 33 +- gui/app/pods/folders/template.hbs | 3 +- gui/app/pods/profile/template.hbs | 2 - gui/app/pods/search/template.hbs | 2 - gui/app/router.js | 12 +- gui/app/services/document.js | 6 +- gui/app/snippets.txt | 411 ------------------ gui/app/styles/base.scss | 3 +- gui/app/styles/view/common.scss | 13 + gui/app/styles/view/document/view.scss | 13 - gui/app/styles/view/folder/settings.scss | 9 +- gui/app/styles/view/layout-left-sidebar.scss | 7 +- .../components/document/document-page.hbs | 2 +- .../components/document/document-tab.hbs | 2 +- .../components/document/document-view.hbs | 10 +- .../components/document/page-heading.hbs | 134 +++--- .../document/sidebar-view-attachments.hbs | 2 +- .../components/document/tab-heading.hbs | 134 +++--- .../components/document/tag-editor.hbs | 2 +- .../components/folder/folder-toolbar.hbs | 23 +- .../components/folder/sidebar-zone.hbs | 58 --- gui/app/utils/model.js | 11 +- gui/tests/helpers/module-for-acceptance.js | 2 +- model/space/permissions.go | 1 + 51 files changed, 517 insertions(+), 868 deletions(-) create mode 100644 gui/app/pods/folder/settings/invitation/controller.js create mode 100644 gui/app/pods/folder/settings/invitation/route.js create mode 100644 gui/app/pods/folder/settings/invitation/template.hbs create mode 100644 gui/app/pods/folder/settings/security/controller.js create mode 100644 gui/app/pods/folder/settings/security/route.js create mode 100644 gui/app/pods/folder/settings/security/template.hbs delete mode 100644 gui/app/snippets.txt diff --git a/domain/document/endpoint.go b/domain/document/endpoint.go index 8d11ee2e..c1f678e0 100644 --- a/domain/document/endpoint.go +++ b/domain/document/endpoint.go @@ -135,24 +135,24 @@ func (h *Handler) DocumentLinks(w http.ResponseWriter, r *http.Request) { response.WriteJSON(w, l) } -// BySpace is an endpoint that returns the documents in a given folder. +// BySpace is an endpoint that returns the documents for given space. func (h *Handler) BySpace(w http.ResponseWriter, r *http.Request) { method := "document.space" ctx := domain.GetRequestContext(r) - folderID := request.Query(r, "folder") + spaceID := request.Query(r, "space") - if len(folderID) == 0 { - response.WriteMissingDataError(w, method, "folder") + if len(spaceID) == 0 { + response.WriteMissingDataError(w, method, "space") return } - if !space.CanViewSpace(ctx, *h.Store, folderID) { + if !space.CanViewSpace(ctx, *h.Store, spaceID) { response.WriteForbiddenError(w) return } - documents, err := h.Store.Document.GetBySpace(ctx, folderID) + documents, err := h.Store.Document.GetBySpace(ctx, spaceID) if len(documents) == 0 { documents = []doc.Document{} diff --git a/domain/document/mysql/store.go b/domain/document/mysql/store.go index b004c9da..04db5292 100644 --- a/domain/document/mysql/store.go +++ b/domain/document/mysql/store.go @@ -134,20 +134,19 @@ func (s Scope) GetBySpace(ctx domain.RequestContext, folderID string) (documents func (s Scope) GetByTag(ctx domain.RequestContext, tag string) (documents []doc.Document, err error) { tagQuery := "tags LIKE '%#" + tag + "#%'" - 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 AND `+tagQuery+` AND labelid IN - (SELECT refid from label WHERE orgid=? AND type=2 AND userid=? - UNION ALL SELECT refid FROM label a where orgid=? AND type=1 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1)) - UNION ALL SELECT refid FROM label a where orgid=? AND type=3 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1))) - ORDER BY title`, - ctx.OrgID, - ctx.OrgID, - ctx.UserID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.UserID) + 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 AND `+tagQuery+` + 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=? AND location='space' + 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=? + )) + ) + ORDER BY title + `, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID) if err != nil { err = errors.Wrap(err, "select documents by tag") @@ -160,19 +159,17 @@ func (s Scope) GetByTag(ctx domain.RequestContext, tag string) (documents []doc. // 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, layout, created, revised FROM document WHERE orgid=? AND template=1 AND labelid IN - (SELECT refid from label WHERE orgid=? AND type=2 AND userid=? - UNION ALL SELECT refid FROM label a where orgid=? AND type=1 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1)) - UNION ALL SELECT refid FROM label a where orgid=? AND type=3 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1))) - ORDER BY title`, - ctx.OrgID, - ctx.OrgID, - ctx.UserID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.UserID) + `SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template, layout, created, revised FROM document WHERE orgid=? AND template=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=? AND location='space' + 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=? + )) + ) + ORDER BY title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID) if err != nil { err = errors.Wrap(err, "select document templates") @@ -185,20 +182,17 @@ 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, layout, created, revised FROM document WHERE orgid=? AND labelid=? AND template=1 AND labelid IN - (SELECT refid from label WHERE orgid=? AND type=2 AND userid=? - UNION ALL SELECT refid FROM label a where orgid=? AND type=1 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1)) - UNION ALL SELECT refid FROM label a where orgid=? AND type=3 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1))) - ORDER BY title`, - ctx.OrgID, - spaceID, - ctx.OrgID, - ctx.UserID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.UserID) + `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 + 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=? AND location='space' + 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=? + )) + ) + ORDER BY title`, ctx.OrgID, spaceID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID) if err == sql.ErrNoRows { err = nil @@ -233,19 +227,17 @@ 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, layout, created, revised FROM document WHERE orgid=? AND template=0 AND labelid IN - (SELECT refid from label WHERE orgid=? AND type=2 AND userid=? - UNION ALL SELECT refid FROM label a where orgid=? AND type=1 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1)) - UNION ALL SELECT refid FROM label a where orgid=? AND type=3 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1))) - ORDER BY title`, - ctx.OrgID, - ctx.OrgID, - ctx.UserID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.UserID) + `SELECT id, refid, orgid, labelid, userid, job, location, title, excerpt, slug, tags, template, layout, created, revised FROM document WHERE orgid=? AND template=0 + 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=? AND location='space' + 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=? + )) + ) + ORDER BY title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID) if err == sql.ErrNoRows { err = nil diff --git a/domain/link/mysql/store.go b/domain/link/mysql/store.go index 85a327e8..7a35f572 100644 --- a/domain/link/mysql/store.go +++ b/domain/link/mysql/store.go @@ -169,21 +169,19 @@ func (s Scope) SearchCandidates(ctx domain.RequestContext, keywords string) (doc keywords = strings.TrimSpace(strings.ToLower(keywords)) likeQuery := "LOWER(title) LIKE '%" + keywords + "%'" - err = s.Runtime.Db.Select(&temp, - `SELECT d.refid as documentid, d. labelid as folderid, d.title, l.label as context - FROM document d LEFT JOIN label l ON d.labelid=l.refid WHERE l.orgid=? AND `+likeQuery+` AND d.labelid IN - (SELECT refid FROM label WHERE orgid=? AND type=2 AND userid=? - UNION ALL SELECT refid FROM label a WHERE orgid=? AND type=1 AND refid IN (SELECT labelid FROM labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1)) - UNION ALL SELECT refid FROM label a WHERE orgid=? AND type=3 AND refid IN (SELECT labelid FROM labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1))) - ORDER BY title`, - ctx.OrgID, - ctx.OrgID, - ctx.UserID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.UserID) + err = s.Runtime.Db.Select(&temp, ` + SELECT d.refid as documentid, d. labelid as folderid, d.title, l.label as context + FROM document d LEFT JOIN label l ON d.labelid=l.refid WHERE l.orgid=? AND `+likeQuery+` + AND d.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=? AND location='space' + 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=? + )) + ) + ORDER BY title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID) if err != nil { err = errors.Wrap(err, "execute search links 1") @@ -210,19 +208,17 @@ func (s Scope) SearchCandidates(ctx domain.RequestContext, keywords string) (doc err = s.Runtime.Db.Select(&temp, `SELECT p.refid as targetid, p.documentid as documentid, p.title as title, p.pagetype as linktype, d.title as context, d.labelid as folderid - FROM page p LEFT JOIN document d ON d.refid=p.documentid WHERE p.orgid=? AND `+likeQuery+` AND d.labelid IN - (SELECT refid FROM label WHERE orgid=? AND type=2 AND userid=? - UNION ALL SELECT refid FROM label a WHERE orgid=? AND type=1 AND refid IN (SELECT labelid FROM labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1)) - UNION ALL SELECT refid FROM label a WHERE orgid=? AND type=3 AND refid IN (SELECT labelid FROM labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1))) - ORDER BY p.title`, - ctx.OrgID, - ctx.OrgID, - ctx.UserID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.UserID) + FROM page p LEFT JOIN document d ON d.refid=p.documentid WHERE p.orgid=? AND `+likeQuery+` + AND d.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=? AND location='space' + 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=? + )) + ) + ORDER BY p.title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID) if err != nil { err = errors.Wrap(err, "execute search links 2") @@ -249,19 +245,17 @@ func (s Scope) SearchCandidates(ctx domain.RequestContext, keywords string) (doc err = s.Runtime.Db.Select(&temp, `SELECT a.refid as targetid, a.documentid as documentid, a.filename as title, a.extension as context, d.labelid as folderid - FROM attachment a LEFT JOIN document d ON d.refid=a.documentid WHERE a.orgid=? AND `+likeQuery+` AND d.labelid IN - (SELECT refid FROM label WHERE orgid=? AND type=2 AND userid=? - UNION ALL SELECT refid FROM label a WHERE orgid=? AND type=1 AND refid IN (SELECT labelid FROM labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1)) - UNION ALL SELECT refid FROM label a WHERE orgid=? AND type=3 AND refid IN (SELECT labelid FROM labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1))) - ORDER BY a.filename`, - ctx.OrgID, - ctx.OrgID, - ctx.UserID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.UserID) + FROM attachment a LEFT JOIN document d ON d.refid=a.documentid WHERE a.orgid=? AND `+likeQuery+` + AND d.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=? AND location='space' + 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=? + )) + ) + ORDER BY a.filename`, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID) if err != nil { err = errors.Wrap(err, "execute search links 3") diff --git a/domain/search/mysql/store.go b/domain/search/mysql/store.go index 40407adc..dfe19ccb 100644 --- a/domain/search/mysql/store.go +++ b/domain/search/mysql/store.go @@ -265,21 +265,26 @@ func (s Scope) matchFullText(ctx domain.RequestContext, keywords, itemType strin AND s.itemtype = ? AND s.documentid = d.refid -- AND d.template = 0 - AND d.labelid IN (SELECT refid from label WHERE orgid=? AND type=2 AND userid=? - UNION ALL SELECT refid FROM label a where orgid=? AND type=1 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1)) - UNION ALL SELECT refid FROM label a where orgid=? AND type=3 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1))) - AND MATCH(s.content) AGAINST(? IN BOOLEAN MODE)` + AND d.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=? AND location='space' + 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=? + )) + ) + AND MATCH(s.content) AGAINST(? IN BOOLEAN MODE)` err = s.Runtime.Db.Select(&r, sql1, ctx.OrgID, itemType, ctx.OrgID, + ctx.OrgID, + ctx.OrgID, ctx.UserID, ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, ctx.UserID, keywords) @@ -318,9 +323,15 @@ func (s Scope) matchLike(ctx domain.RequestContext, keywords, itemType string) ( AND s.itemtype = ? AND s.documentid = d.refid -- AND d.template = 0 - AND d.labelid IN (SELECT refid from label WHERE orgid=? AND type=2 AND userid=? - UNION ALL SELECT refid FROM label a where orgid=? AND type=1 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1)) - UNION ALL SELECT refid FROM label a where orgid=? AND type=3 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1))) + AND d.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=? AND location='space' + 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=? + )) + ) AND s.content LIKE ?` err = s.Runtime.Db.Select(&r, @@ -328,11 +339,10 @@ func (s Scope) matchLike(ctx domain.RequestContext, keywords, itemType string) ( ctx.OrgID, itemType, ctx.OrgID, + ctx.OrgID, + ctx.OrgID, ctx.UserID, ctx.OrgID, - ctx.OrgID, - ctx.OrgID, - ctx.OrgID, ctx.UserID, keywords) diff --git a/domain/storer.go b/domain/storer.go index 94ad8543..04729e76 100644 --- a/domain/storer.go +++ b/domain/storer.go @@ -75,7 +75,7 @@ type UserStorer interface { GetBySerial(ctx RequestContext, serial string) (u user.User, err error) GetActiveUsersForOrganization(ctx RequestContext) (u []user.User, err error) GetUsersForOrganization(ctx RequestContext) (u []user.User, err error) - GetSpaceUsers(ctx RequestContext, folderID string) (u []user.User, err error) + GetSpaceUsers(ctx RequestContext, spaceID string) (u []user.User, err error) GetVisibleUsers(ctx RequestContext) (u []user.User, err error) UpdateUser(ctx RequestContext, u user.User) (err error) UpdateUserPassword(ctx RequestContext, userID, salt, password string) (err error) diff --git a/domain/user/mysql/store.go b/domain/user/mysql/store.go index 7df4f64f..a97eea89 100644 --- a/domain/user/mysql/store.go +++ b/domain/user/mysql/store.go @@ -184,14 +184,16 @@ func (s Scope) GetUsersForOrganization(ctx domain.RequestContext) (u []user.User } // GetSpaceUsers returns a slice containing all user records for given folder. -func (s Scope) GetSpaceUsers(ctx domain.RequestContext, folderID string) (u []user.User, err error) { - err = s.Runtime.Db.Select(&u, - `SELECT u.id, u.refid, u.firstname, u.lastname, u.email, u.initials, u.password, u.salt, u.reset, u.created, u.revised +func (s Scope) GetSpaceUsers(ctx domain.RequestContext, spaceID string) (u []user.User, err error) { + err = s.Runtime.Db.Select(&u, ` + SELECT u.id, u.refid, u.firstname, u.lastname, u.email, u.initials, u.password, u.salt, u.reset, u.created, u.revised FROM user u, account a - WHERE u.refid IN (SELECT userid from labelrole WHERE orgid=? AND labelid=?) - AND a.orgid=? AND u.refid = a.userid AND a.active=1 - ORDER BY u.firstname, u.lastname`, - ctx.OrgID, folderID, ctx.OrgID) + WHERE a.orgid=? AND u.refid = a.userid AND a.active=1 AND u.refid IN ( + SELECT whoid from permission WHERE orgid=? AND who='user' AND scope='object' AND location='space' AND refid=? UNION ALL + SELECT r.userid from rolemember r LEFT JOIN permission p ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.scope='object' AND p.location='space' AND p.refid=? + ) + ORDER BY u.firstname, u.lastname; + `, ctx.OrgID, ctx.OrgID, spaceID, ctx.OrgID, spaceID) if err != nil { err = errors.Wrap(err, fmt.Sprintf("get space users for org %s", ctx.OrgID)) diff --git a/gui/app/components/document/document-page.js b/gui/app/components/document/document-page.js index f5499723..b1ca0a90 100644 --- a/gui/app/components/document/document-page.js +++ b/gui/app/components/document/document-page.js @@ -33,7 +33,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, { } this.set('meta', meta); - if (this.get('toEdit') === this.get('page.id') && this.get('isEditor')) { + if (this.get('toEdit') === this.get('page.id') && this.get('permissions.documentEdit')) { this.send('onEdit'); } }); diff --git a/gui/app/components/document/page-heading.js b/gui/app/components/document/page-heading.js index 0eddb42e..c88f4f03 100644 --- a/gui/app/components/document/page-heading.js +++ b/gui/app/components/document/page-heading.js @@ -72,6 +72,13 @@ export default Ember.Component.extend(TooltipMixin, { return `move-dialog-${id}`; }), + hasMenuPermissions: computed('permissions', function() { + let permissions = this.get('permissions'); + + return permissions.get('documentDelete') || permissions.get('documentCopy') || + permissions.get('documentMove') || permissions.get('documentTemplate');; + }), + didRender() { $("#" + this.get('blockTitleId')).removeClass('error'); $("#" + this.get('blockExcerptId')).removeClass('error'); @@ -131,7 +138,7 @@ export default Ember.Component.extend(TooltipMixin, { }; this.attrs.onSavePageAsBlock(block); - + this.set('menuOpen', false); this.set('blockTitle', ''); this.set('blockExcerpt', ''); diff --git a/gui/app/components/document/sidebar-view-index.js b/gui/app/components/document/sidebar-view-index.js index bbbc141e..9de277a8 100644 --- a/gui/app/components/document/sidebar-view-index.js +++ b/gui/app/components/document/sidebar-view-index.js @@ -32,7 +32,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, { didReceiveAttrs: function () { this._super(...arguments); - + this.set('showToc', is.not.undefined(this.get('pages')) && this.get('pages').get('length') > 0); if (is.not.null(this.get('currentPageId'))) { @@ -42,7 +42,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, { didRender: function () { this._super(...arguments); - + if (this.session.authenticated) { this.addTooltip(document.getElementById("toc-up-button")); this.addTooltip(document.getElementById("toc-down-button")); @@ -53,13 +53,13 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, { didInsertElement() { this._super(...arguments); - + this.eventBus.subscribe('documentPageAdded', this, 'onDocumentPageAdded'); }, willDestroyElement() { this._super(...arguments); - + this.eventBus.unsubscribe('documentPageAdded'); this.destroyTooltips(); }, @@ -77,7 +77,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, { let page = _.findWhere(toc, { id: pageId }); let state = tocUtil.getState(toc, page); - if (!this.get('isEditor') || is.empty(pageId)) { + if (!this.get('permissions.documentEdit') || is.empty(pageId)) { state.actionablePage = false; state.upDisabled = state.downDisabled = state.indentDisabled = state.outdentDisabled = true; } diff --git a/gui/app/components/document/tab-heading.js b/gui/app/components/document/tab-heading.js index d086eef0..e560f7e9 100644 --- a/gui/app/components/document/tab-heading.js +++ b/gui/app/components/document/tab-heading.js @@ -73,6 +73,13 @@ export default Ember.Component.extend(TooltipMixin, { return `move-dialog-${id}`; }), + hasMenuPermissions: computed('permissions', function() { + let permissions = this.get('permissions'); + + return permissions.get('documentDelete') || permissions.get('documentCopy') || + permissions.get('documentMove') || permissions.get('documentTemplate');; + }), + didRender() { $("#" + this.get('blockTitleId')).removeClass('error'); $("#" + this.get('blockExcerptId')).removeClass('error'); diff --git a/gui/app/components/document/tag-editor.js b/gui/app/components/document/tag-editor.js index 77753eeb..dc43b77a 100644 --- a/gui/app/components/document/tag-editor.js +++ b/gui/app/components/document/tag-editor.js @@ -14,7 +14,6 @@ import Ember from 'ember'; export default Ember.Component.extend({ documentTags: [], tagz: [], - isEditor: false, newTag: "", maxTags: 3, canAdd: false, diff --git a/gui/app/components/folder/folder-toolbar.js b/gui/app/components/folder/folder-toolbar.js index 2fd204ec..b5902b7a 100644 --- a/gui/app/components/folder/folder-toolbar.js +++ b/gui/app/components/folder/folder-toolbar.js @@ -14,22 +14,36 @@ import NotifierMixin from '../../mixins/notifier'; import TooltipMixin from '../../mixins/tooltip'; import AuthMixin from '../../mixins/auth'; +const { + inject: { service } +} = Ember; + export default Ember.Component.extend(NotifierMixin, TooltipMixin, AuthMixin, { - folderService: Ember.inject.service('folder'), - session: Ember.inject.service(), - appMeta: Ember.inject.service(), + folderService: service('folder'), + session: service(), + appMeta: service(), + pinned: service(), showToolbar: false, folder: {}, busy: false, moveFolderId: "", drop: null, + pinState : { + isPinned: false, + pinId: '', + newName: '', + }, didReceiveAttrs() { - console.log(this.get('permissions')); let targets = _.reject(this.get('folders'), { id: this.get('folder').get('id') }); + let folder = this.get('folder'); + this.set('pinState.pinId', this.get('pinned').isSpacePinned(folder.get('id'))); + this.set('pinState.isPinned', this.get('pinState.pinId') !== ''); + this.set('pinState.newName', folder.get('name').substring(0,3).toUpperCase()); + this.set('movedFolderOptions', targets); }, @@ -61,6 +75,35 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, AuthMixin, { }, actions: { + onUnpin() { + this.get('pinned').unpinItem(this.get('pinState.pinId')).then(() => { + this.set('pinState.isPinned', false); + this.set('pinState.pinId', ''); + this.eventBus.publish('pinChange'); + }); + }, + + onPin() { + let pin = { + pin: this.get('pinState.newName'), + documentId: '', + folderId: this.get('folder.id') + }; + + if (is.empty(pin.pin)) { + $('#pin-space-name').addClass('error').focus(); + return false; + } + + this.get('pinned').pinItem(pin).then((pin) => { + this.set('pinState.isPinned', true); + this.set('pinState.pinId', pin.get('id')); + this.eventBus.publish('pinChange'); + }); + + return true; + }, + deleteDocuments() { this.attrs.onDeleteDocument(); }, diff --git a/gui/app/components/folder/sidebar-zone.js b/gui/app/components/folder/sidebar-zone.js index 8337a6d4..6267b29e 100644 --- a/gui/app/components/folder/sidebar-zone.js +++ b/gui/app/components/folder/sidebar-zone.js @@ -14,28 +14,7 @@ import TooltipMixin from '../../mixins/tooltip'; import NotifierMixin from '../../mixins/notifier'; import AuthMixin from '../../mixins/auth'; -const { - inject: { service } -} = Ember; - export default Ember.Component.extend(TooltipMixin, NotifierMixin, AuthMixin, { - folderService: service('folder'), - templateService: service('template'), - appMeta: service(), - pinned: service(), - publicFolders: [], - protectedFolders: [], - privateFolders: [], - hasPublicFolders: false, - hasProtectedFolders: false, - hasPrivateFolders: false, - newFolder: "", - menuOpen: false, - pinState : { - isPinned: false, - pinId: '', - newName: '', - }, tab: '', init() { @@ -46,15 +25,6 @@ export default Ember.Component.extend(TooltipMixin, NotifierMixin, AuthMixin, { } }, - didReceiveAttrs() { - if (!this.get('noFolder')) { - let folder = this.get('folder'); - this.set('pinState.pinId', this.get('pinned').isSpacePinned(folder.get('id'))); - this.set('pinState.isPinned', this.get('pinState.pinId') !== ''); - this.set('pinState.newName', folder.get('name').substring(0,3).toUpperCase()); - } - }, - actions: { onAddSpace(m) { this.attrs.onAddSpace(m); @@ -64,38 +34,5 @@ export default Ember.Component.extend(TooltipMixin, NotifierMixin, AuthMixin, { onChangeTab(tab) { this.set('tab', tab); }, - - onMenuOpen() { - this.set('menuOpen', !this.get('menuOpen')); - }, - - onUnpin() { - this.get('pinned').unpinItem(this.get('pinState.pinId')).then(() => { - this.set('pinState.isPinned', false); - this.set('pinState.pinId', ''); - this.eventBus.publish('pinChange'); - }); - }, - - onPin() { - let pin = { - pin: this.get('pinState.newName'), - documentId: '', - folderId: this.get('folder.id') - }; - - if (is.empty(pin.pin)) { - $('#pin-space-name').addClass('error').focus(); - return false; - } - - this.get('pinned').pinItem(pin).then((pin) => { - this.set('pinState.isPinned', true); - this.set('pinState.pinId', pin.get('id')); - this.eventBus.publish('pinChange'); - }); - - return true; - }, } }); diff --git a/gui/app/pods/customize/route.js b/gui/app/pods/customize/route.js index 0f5e0197..a24bba23 100644 --- a/gui/app/pods/customize/route.js +++ b/gui/app/pods/customize/route.js @@ -1,11 +1,11 @@ // Copyright 2016 Documize Inc. . All rights reserved. // -// This software (Documize Community Edition) is licensed under +// 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 . +// by contacting . // // https://documize.com @@ -18,4 +18,4 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, { this.transitionTo('customize.general'); } }, -}); \ No newline at end of file +}); diff --git a/gui/app/pods/customize/template.hbs b/gui/app/pods/customize/template.hbs index 1e00c3f2..cf815854 100644 --- a/gui/app/pods/customize/template.hbs +++ b/gui/app/pods/customize/template.hbs @@ -1,8 +1,6 @@ {{layout/zone-navigation}} {{#layout/zone-container}} {{#layout/zone-sidebar}} - diff --git a/gui/app/pods/document/block/template.hbs b/gui/app/pods/document/block/template.hbs index 2ab87b96..d4bd7258 100644 --- a/gui/app/pods/document/block/template.hbs +++ b/gui/app/pods/document/block/template.hbs @@ -7,7 +7,7 @@ arrow_back {{model.document.name}} {{/link-to}} - {{document/document-heading document=model.document isEditor=false}} + {{document/document-heading document=model.document}} {{document/block-editor document=model.document folder=model.folder block=model.block onCancel=(action 'onCancel') onAction=(action 'onAction')}} diff --git a/gui/app/pods/document/history/template.hbs b/gui/app/pods/document/history/template.hbs index 6fbaf81a..cdb5247c 100644 --- a/gui/app/pods/document/history/template.hbs +++ b/gui/app/pods/document/history/template.hbs @@ -7,7 +7,7 @@ arrow_back {{model.document.name}} {{/link-to}} - {{document/document-heading document=model.document isEditor=false}} + {{document/document-heading document=model.document}} {{#if hasRevisions}} {{document/document-history document=model.document folder=model.folder pages=model.pages revisions=model.revisions diff=model.diff onFetchDiff=(action 'onFetchDiff') onRollback=(action 'onRollback')}} diff --git a/gui/app/pods/document/index/route.js b/gui/app/pods/document/index/route.js index f1155e38..6c1179ad 100644 --- a/gui/app/pods/document/index/route.js +++ b/gui/app/pods/document/index/route.js @@ -30,7 +30,7 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, { pages: this.get('documentService').getPages(this.modelFor('document').document.get('id')), links: this.modelFor('document').links, sections: this.modelFor('document').sections, - permissions: this.get('folderService').get('permissions') + permissions: this.modelFor('document').permissions }); } }); diff --git a/gui/app/pods/folder/index/route.js b/gui/app/pods/folder/index/route.js index cf79792b..3ec56e14 100644 --- a/gui/app/pods/folder/index/route.js +++ b/gui/app/pods/folder/index/route.js @@ -18,7 +18,6 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, { return Ember.RSVP.hash({ folder: this.modelFor('folder').folder, - isEditor: this.modelFor('folder').isEditor, permissions: this.modelFor('folder').permissions, folders: this.modelFor('folder').folders, documents: this.modelFor('folder').documents, diff --git a/gui/app/pods/folder/route.js b/gui/app/pods/folder/route.js index 5f2f6214..20e0ee95 100644 --- a/gui/app/pods/folder/route.js +++ b/gui/app/pods/folder/route.js @@ -39,7 +39,7 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, { folder: this.get('folder'), permissions: this.get('permissions'), folders: this.get('folderService').getAll(), - documents: this.get('documentService').getAllByFolder(params.folder_id), + documents: this.get('documentService').getAllBySpace(params.folder_id), templates: this.get('templateService').getSavedTemplates(params.folder_id) }); }, diff --git a/gui/app/pods/folder/settings/invitation/controller.js b/gui/app/pods/folder/settings/invitation/controller.js new file mode 100644 index 00000000..bef4c71c --- /dev/null +++ b/gui/app/pods/folder/settings/invitation/controller.js @@ -0,0 +1,15 @@ +// Copyright 2016 Documize Inc. . 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 . +// +// https://documize.com + +import Ember from 'ember'; + +export default Ember.Controller.extend({ +}); diff --git a/gui/app/pods/folder/settings/invitation/route.js b/gui/app/pods/folder/settings/invitation/route.js new file mode 100644 index 00000000..c289356a --- /dev/null +++ b/gui/app/pods/folder/settings/invitation/route.js @@ -0,0 +1,25 @@ +// Copyright 2016 Documize Inc. . 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 . +// +// https://documize.com + +import Ember from 'ember'; +import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin'; + +export default Ember.Route.extend(AuthenticatedRouteMixin, { + model() { + this.get('browser').setTitle(this.modelFor('folder').folder.get('name')); + + return Ember.RSVP.hash({ + folder: this.modelFor('folder').folder, + permissions: this.modelFor('folder').permissions, + folders: this.modelFor('folder').folders + }); + } +}); diff --git a/gui/app/pods/folder/settings/invitation/template.hbs b/gui/app/pods/folder/settings/invitation/template.hbs new file mode 100644 index 00000000..64fad17d --- /dev/null +++ b/gui/app/pods/folder/settings/invitation/template.hbs @@ -0,0 +1 @@ +{{folder/invite-user folders=model.folders folder=model.folder}} diff --git a/gui/app/pods/folder/settings/route.js b/gui/app/pods/folder/settings/route.js index c289356a..b065f731 100644 --- a/gui/app/pods/folder/settings/route.js +++ b/gui/app/pods/folder/settings/route.js @@ -13,6 +13,12 @@ import Ember from 'ember'; import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin'; export default Ember.Route.extend(AuthenticatedRouteMixin, { + beforeModel: function (transition) { + if (is.equal(transition.targetName, 'folder.settings.index')) { + this.transitionTo('folder.settings.security'); + } + }, + model() { this.get('browser').setTitle(this.modelFor('folder').folder.get('name')); diff --git a/gui/app/pods/folder/settings/security/controller.js b/gui/app/pods/folder/settings/security/controller.js new file mode 100644 index 00000000..bef4c71c --- /dev/null +++ b/gui/app/pods/folder/settings/security/controller.js @@ -0,0 +1,15 @@ +// Copyright 2016 Documize Inc. . 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 . +// +// https://documize.com + +import Ember from 'ember'; + +export default Ember.Controller.extend({ +}); diff --git a/gui/app/pods/folder/settings/security/route.js b/gui/app/pods/folder/settings/security/route.js new file mode 100644 index 00000000..c289356a --- /dev/null +++ b/gui/app/pods/folder/settings/security/route.js @@ -0,0 +1,25 @@ +// Copyright 2016 Documize Inc. . 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 . +// +// https://documize.com + +import Ember from 'ember'; +import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin'; + +export default Ember.Route.extend(AuthenticatedRouteMixin, { + model() { + this.get('browser').setTitle(this.modelFor('folder').folder.get('name')); + + return Ember.RSVP.hash({ + folder: this.modelFor('folder').folder, + permissions: this.modelFor('folder').permissions, + folders: this.modelFor('folder').folders + }); + } +}); diff --git a/gui/app/pods/folder/settings/security/template.hbs b/gui/app/pods/folder/settings/security/template.hbs new file mode 100644 index 00000000..99d66823 --- /dev/null +++ b/gui/app/pods/folder/settings/security/template.hbs @@ -0,0 +1 @@ +{{folder/permission-admin folders=model.folders folder=model.folder}} diff --git a/gui/app/pods/folder/settings/template.hbs b/gui/app/pods/folder/settings/template.hbs index e4b954e8..a46ba99b 100644 --- a/gui/app/pods/folder/settings/template.hbs +++ b/gui/app/pods/folder/settings/template.hbs @@ -1,36 +1,33 @@ {{#layout/zone-container}} - {{#layout/zone-sidebar}} - {{/layout/zone-sidebar}} - {{#layout/zone-content}} -
-

{{model.folder.name}}

+
+ {{#link-to 'folder' model.folder.id model.folder.slug}} +
+ arrow_back +
{{model.folder.name}}
+
+ {{/link-to}}
- {{#link-to 'folder' model.folder.id model.folder.slug class="vertical-top"}} - arrow_back back to space - {{/link-to}}
- {{#if isAuthProviderDocumize}} - {{folder/invite-user folders=model.folders folder=model.folder}} -
- {{/if}} + {{outlet}} - {{folder/permission-admin folders=model.folders folder=model.folder}}
-{{/layout/zone-content}} - + {{/layout/zone-content}} {{/layout/zone-container}} \ No newline at end of file diff --git a/gui/app/pods/folders/template.hbs b/gui/app/pods/folders/template.hbs index f15d8e93..8b3f2432 100644 --- a/gui/app/pods/folders/template.hbs +++ b/gui/app/pods/folders/template.hbs @@ -1,8 +1,7 @@ {{layout/zone-navigation}} {{#layout/zone-container}} {{#layout/zone-sidebar}} - {{folder/sidebar-zone folders=model noFolder=true isFolderOwner=false isEditor=false - onAddSpace=(action 'onAddSpace')}} + {{folder/sidebar-zone folders=model noFolder=true onAddSpace=(action 'onAddSpace')}} {{/layout/zone-sidebar}} {{#layout/zone-content}} {{/layout/zone-content}} diff --git a/gui/app/pods/profile/template.hbs b/gui/app/pods/profile/template.hbs index 230554d9..f5392885 100644 --- a/gui/app/pods/profile/template.hbs +++ b/gui/app/pods/profile/template.hbs @@ -1,8 +1,6 @@ {{layout/zone-navigation}} {{#layout/zone-container}} {{#layout/zone-sidebar}} - diff --git a/gui/app/pods/search/template.hbs b/gui/app/pods/search/template.hbs index 44c47f48..f7277a4b 100644 --- a/gui/app/pods/search/template.hbs +++ b/gui/app/pods/search/template.hbs @@ -2,8 +2,6 @@ {{#layout/zone-container}} {{#layout/zone-sidebar}} - diff --git a/gui/app/router.js b/gui/app/router.js index 3fad9b5a..53776873 100644 --- a/gui/app/router.js +++ b/gui/app/router.js @@ -26,7 +26,17 @@ export default Router.map(function () { }, function() { this.route('settings', { path: 'settings' - }); + }, function () { + this.route('security', { + path: 'security' + }); + this.route('invitation', { + path: 'invitation' + }); + this.route('category', { + path: 'category' + }); + }) }); this.route('document', { diff --git a/gui/app/services/document.js b/gui/app/services/document.js index a964f607..fb2ea79a 100644 --- a/gui/app/services/document.js +++ b/gui/app/services/document.js @@ -33,9 +33,9 @@ export default Ember.Service.extend({ }); }, - // Returns all documents for specified folder. - getAllByFolder(folderId) { - return this.get('ajax').request(`documents?folder=${folderId}`, { + // Returns all documents for specified space. + getAllBySpace(spaceId) { + return this.get('ajax').request(`documents?space=${spaceId}`, { method: "GET" }).then((response) => { let documents = Ember.ArrayProxy.create({ diff --git a/gui/app/snippets.txt b/gui/app/snippets.txt deleted file mode 100644 index fd551c48..00000000 --- a/gui/app/snippets.txt +++ /dev/null @@ -1,411 +0,0 @@ -********************************** -********************************** -***** document -********************************** -********************************** - -{{layout/zone-navigation}} - -{{#layout/zone-sidebar}} - {{document/document-sidebar document=model.document folder=model.folder pages=model.pages page=model.page isEditor=model.isEditor sections=model.sections - onAddSection=(action 'onAddSection') onInsertBlock=(action 'onInsertBlock') onDeleteBlock=(action 'onDeleteBlock') changePageSequence=(action 'onPageSequenceChange') changePageLevel=(action 'onPageLevelChange') gotoPage=(action 'gotoPage')}} -{{/layout/zone-sidebar}} - -{{#layout/zone-content}} - {{document/document-toolbar document=model.document pages=model.pages tabs=model.tabs folder=model.folder isEditor=model.isEditor - onSaveTemplate=(action 'onSaveTemplate') onSaveMeta=(action 'onSaveMeta') onDocumentDelete=(action 'onDocumentDelete')}} - - {{outlet}} -{{/layout/zone-content}} - -// Copyright 2016 Documize Inc. . 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 . -// -// https://documize.com - -import Ember from 'ember'; -import NotifierMixin from '../../mixins/notifier'; - -export default Ember.Controller.extend(NotifierMixin, { - documentService: Ember.inject.service('document'), - templateService: Ember.inject.service('template'), - sectionService: Ember.inject.service('section'), - page: null, - folder: {}, - pages: [], - - // Jump to the right part of the document. - scrollToPage(pageId) { - Ember.run.schedule('afterRender', function () { - let dest; - let target = "#page-title-" + pageId; - let targetOffset = $(target).offset(); - - if (is.undefined(targetOffset)) { - return; - } - - dest = targetOffset.top > $(document).height() - $(window).height() ? $(document).height() - $(window).height() : targetOffset.top; - // small correction to ensure we also show page title - dest = dest > 50 ? dest - 74 : dest; - - $("html,body").animate({ - scrollTop: dest - }, 500, "linear"); - $(".toc-index-item").removeClass("selected"); - $("#index-" + pageId).addClass("selected"); - }); - }, - - actions: { - gotoPage(pageId) { - if (is.null(pageId)) { - return; - } - - this.scrollToPage(pageId); - }, - - onPageSequenceChange(changes) { - this.get('documentService').changePageSequence(this.get('model.document.id'), changes).then(() => { - _.each(changes, (change) => { - let pageContent = _.findWhere(this.get('model.pages'), { - id: change.pageId - }); - - if (is.not.undefined(pageContent)) { - pageContent.set('sequence', change.sequence); - } - }); - - this.set('model.pages', this.get('model.pages').sortBy('sequence')); - this.get('target.router').refresh(); - }); - }, - - onPageLevelChange(changes) { - this.get('documentService').changePageLevel(this.get('model.document.id'), changes).then(() => { - _.each(changes, (change) => { - let pageContent = _.findWhere(this.get('model.pages'), { - id: change.pageId - }); - - if (is.not.undefined(pageContent)) { - pageContent.set('level', change.level); - } - }); - - let pages = this.get('model.pages'); - pages = pages.sortBy('sequence'); - this.set('model.pages', []); - this.set('model.pages', pages); - this.get('target.router').refresh(); - }); - }, - - onSaveTemplate(name, desc) { - this.get('templateService').saveAsTemplate(this.get('model.document.id'), name, desc).then(function () {}); - }, - - onSaveMeta(doc) { - this.get('documentService').save(doc).then(() => { - this.transitionToRoute('document.index'); - }); - }, - - onAddSection(section) { - this.audit.record("added-section-" + section.get('contentType')); - - let page = { - documentId: this.get('model.document.id'), - title: `${section.get('title')}`, - level: 1, - sequence: 0, - body: "", - contentType: section.get('contentType'), - pageType: section.get('pageType') - }; - - let meta = { - documentId: this.get('model.document.id'), - rawBody: "", - config: "" - }; - - let model = { - page: page, - meta: meta - }; - - this.get('documentService').addPage(this.get('model.document.id'), model).then((newPage) => { - let data = this.get('store').normalize('page', newPage); - this.get('store').push(data); - - this.get('documentService').getPages(this.get('model.document.id')).then((pages) => { - this.set('model.pages', pages.filterBy('pageType', 'section')); - this.set('model.tabs', pages.filterBy('pageType', 'tab')); - - this.get('documentService').getPageMeta(this.get('model.document.id'), newPage.id).then(() => { - this.transitionToRoute('document.edit', - this.get('model.folder.id'), - this.get('model.folder.slug'), - this.get('model.document.id'), - this.get('model.document.slug'), - newPage.id); - }); - }); - }); - }, - - onInsertBlock(block) { - this.audit.record("added-content-block-" + block.get('contentType')); - - let page = { - documentId: this.get('model.document.id'), - title: `${block.get('title')}`, - level: 1, - sequence: 0, - body: block.get('body'), - contentType: block.get('contentType'), - pageType: block.get('pageType'), - blockId: block.get('id') - }; - - let meta = { - documentId: this.get('model.document.id'), - rawBody: block.get('rawBody'), - config: block.get('config'), - externalSource: block.get('externalSource') - }; - - let model = { - page: page, - meta: meta - }; - - this.get('documentService').addPage(this.get('model.document.id'), model).then((newPage) => { - let data = this.get('store').normalize('page', newPage); - this.get('store').push(data); - - this.get('documentService').getPages(this.get('model.document.id')).then((pages) => { - this.set('model.pages', pages.filterBy('pageType', 'section')); - this.set('model.tabs', pages.filterBy('pageType', 'tab')); - - this.get('documentService').getPageMeta(this.get('model.document.id'), newPage.id).then(() => { - this.transitionToRoute('document.edit', - this.get('model.folder.id'), - this.get('model.folder.slug'), - this.get('model.document.id'), - this.get('model.document.slug'), - newPage.id); - }); - }); - }); - }, - - onDeleteBlock(blockId) { - this.get('sectionService').deleteBlock(blockId).then(() => { - this.audit.record("deleted-block"); - this.send("showNotification", "Deleted"); - this.transitionToRoute('document.index'); - }); - }, - - onDocumentDelete() { - this.get('documentService').deleteDocument(this.get('model.document.id')).then(() => { - this.audit.record("deleted-page"); - this.send("showNotification", "Deleted"); - this.transitionToRoute('folder', this.get('model.folder.id'), this.get('model.folder.slug')); - }); - } - } -}); - - -********************************** -********************************** -***** document/index -********************************** -********************************** - -{{document/document-view document=model.document links=model.links allPages=model.allPages tabs=model.tabs pages=model.pages folder=model.folder folders=model.folders isEditor=model.isEditor gotoPage=(action 'gotoPage') onAddBlock=(action 'onAddBlock') onCopyPage=(action 'onCopyPage') onMovePage=(action 'onMovePage') onDeletePage=(action 'onPageDeleted')}} - - -// Copyright 2016 Documize Inc. . 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 . -// -// https://documize.com - -import Ember from 'ember'; -import NotifierMixin from '../../../mixins/notifier'; - -export default Ember.Controller.extend(NotifierMixin, { - documentService: Ember.inject.service('document'), - sectionService: Ember.inject.service('section'), - queryParams: ['page'], - - // Jump to the right part of the document. - scrollToPage(pageId) { - Ember.run.schedule('afterRender', function () { - let dest; - let target = "#page-title-" + pageId; - let targetOffset = $(target).offset(); - - if (is.undefined(targetOffset)) { - return; - } - - dest = targetOffset.top > $(document).height() - $(window).height() ? $(document).height() - $(window).height() : targetOffset.top; - // small correction to ensure we also show page title - dest = dest > 50 ? dest - 74 : dest; - - $("html,body").animate({ - scrollTop: dest - }, 500, "linear"); - $(".toc-index-item").removeClass("selected"); - $("#index-" + pageId).addClass("selected"); - }); - }, - - actions: { - gotoPage(pageId) { - if (is.null(pageId)) { - return; - } - - this.scrollToPage(pageId); - }, - - onPageSequenceChange(changes) { - this.get('documentService').changePageSequence(this.get('model.document.id'), changes).then(() => { - _.each(changes, (change) => { - let pageContent = _.findWhere(this.get('model.pages'), { - id: change.pageId - }); - - if (is.not.undefined(pageContent)) { - pageContent.set('sequence', change.sequence); - } - }); - - this.set('model.pages', this.get('model.pages').sortBy('sequence')); - this.get('target.router').refresh(); - }); - }, - - onPageLevelChange(changes) { - this.get('documentService').changePageLevel(this.get('model.document.id'), changes).then(() => { - _.each(changes, (change) => { - let pageContent = _.findWhere(this.get('model.pages'), { - id: change.pageId - }); - - if (is.not.undefined(pageContent)) { - pageContent.set('level', change.level); - } - }); - - let pages = this.get('model.pages'); - pages = pages.sortBy('sequence'); - this.set('model.pages', pages); - - this.get('target.router').refresh(); - }); - }, - - onAddBlock(block) { - this.get('sectionService').addBlock(block).then(() => { - this.showNotification("Published"); - }); - }, - - onCopyPage(pageId, targetDocumentId) { - let documentId = this.get('model.document.id'); - this.get('documentService').copyPage(documentId, pageId, targetDocumentId).then(() => { - this.showNotification("Copied"); - - // refresh data if copied to same document - if (documentId === targetDocumentId) { - this.get('target.router').refresh(); - } - }); - }, - - onMovePage(pageId, targetDocumentId) { - let documentId = this.get('model.document.id'); - - this.get('documentService').copyPage(documentId, pageId, targetDocumentId).then(() => { - this.showNotification("Moved"); - - this.send('onPageDeleted', { id: pageId, children: false }); - }); - }, - - onPageDeleted(deletePage) { - let documentId = this.get('model.document.id'); - let pages = this.get('model.pages'); - let deleteId = deletePage.id; - let deleteChildren = deletePage.children; - let page = _.findWhere(pages, { - id: deleteId - }); - let pageIndex = _.indexOf(pages, page, false); - let pendingChanges = []; - - this.audit.record("deleted-page"); - - // select affected pages - for (var i = pageIndex + 1; i < pages.get('length'); i++) { - if (pages[i].get('level') <= page.get('level')) { - break; - } - - pendingChanges.push({ - pageId: pages[i].get('id'), - level: pages[i].get('level') - 1 - }); - } - - if (deleteChildren) { - // nuke of page tree - pendingChanges.push({ - pageId: deleteId - }); - - this.get('documentService').deletePages(documentId, deleteId, pendingChanges).then(() => { - // update our models so we don't have to reload from db - for (var i = 0; i < pendingChanges.length; i++) { - let pageId = pendingChanges[i].pageId; - this.set('model.pages', _.reject(pages, function (p) { //jshint ignore: line - return p.get('id') === pageId; - })); - } - - this.set('model.pages', _.sortBy(pages, "sequence")); - this.get('target.router').refresh(); - }); - } else { - // page delete followed by re-leveling child pages - this.get('documentService').deletePage(documentId, deleteId).then(() => { - this.set('model.pages', _.reject(pages, function (p) { - return p.get('id') === deleteId; - })); - - this.send('onPageLevelChange', pendingChanges); - }); - } - } - } -}); diff --git a/gui/app/styles/base.scss b/gui/app/styles/base.scss index d47ae371..916bfae5 100644 --- a/gui/app/styles/base.scss +++ b/gui/app/styles/base.scss @@ -107,11 +107,10 @@ video.responsive-video { html { overflow-y: scroll; font-family: $font-regular; - background-color: $color-off-white; font-size: 14px; height: 100%; -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + -moz-osx-font-smoothing: grayscale; text-shadow: 1px 1px 1px rgba(0,0,0,0.004); } diff --git a/gui/app/styles/view/common.scss b/gui/app/styles/view/common.scss index 56dac851..3d0908fb 100644 --- a/gui/app/styles/view/common.scss +++ b/gui/app/styles/view/common.scss @@ -13,3 +13,16 @@ color: $color-gray; } } + +.back-to-space { + margin: 10px 0; + + > a { + > .regular-button { + > .name { + // max-width: 150px; + // @extend .truncate; + } + } + } +} diff --git a/gui/app/styles/view/document/view.scss b/gui/app/styles/view/document/view.scss index 06f5dc03..f47571c3 100644 --- a/gui/app/styles/view/document/view.scss +++ b/gui/app/styles/view/document/view.scss @@ -1,17 +1,4 @@ .zone-document-content { - > .back-to-space { - margin: 10px 0; - - > a { - > .regular-button { - > .name { - // max-width: 150px; - // @extend .truncate; - } - } - } - } - .doc-title { font-size: 2rem; margin: 30px 0 10px; diff --git a/gui/app/styles/view/folder/settings.scss b/gui/app/styles/view/folder/settings.scss index c5d92fb0..cd3d7d50 100644 --- a/gui/app/styles/view/folder/settings.scss +++ b/gui/app/styles/view/folder/settings.scss @@ -14,16 +14,13 @@ padding: 8px 0; > .permission-name-cell { - padding: 10px 5px; font-size: 1.1rem; + background-color: $color-off-white; + padding: 10px 10px; } > .permission-roles-cell { - background-color: $color-off-white; - margin-top: 10px; - margin-left: 40px; - padding: 10px 10px; - display: inline-block; + margin: 15px 0 20px 40px; > .role-category { color: $color-gray; diff --git a/gui/app/styles/view/layout-left-sidebar.scss b/gui/app/styles/view/layout-left-sidebar.scss index eb5e4663..7df8ce8b 100644 --- a/gui/app/styles/view/layout-left-sidebar.scss +++ b/gui/app/styles/view/layout-left-sidebar.scss @@ -10,6 +10,7 @@ $sidebar-width: 400px; } #sidebar-wrapper { + background-color: $color-off-white; z-index: 888; position: fixed; overflow-x: hidden; @@ -105,11 +106,11 @@ $sidebar-width: 400px; display: inline-block; width: 340px; padding: 40px 20px 0px 20px; - margin-left: 60px; + margin-left: 20px; > .pinner { cursor: pointer; - + > .material-icons { color: $color-primary; } @@ -138,7 +139,7 @@ $sidebar-width: 400px; .sidebar-wrapper { padding: 40px 20px 40px 20px; - margin-left: 60px; + margin-left: 20px; .sidebar-panel { width: 300px; diff --git a/gui/app/templates/components/document/document-page.hbs b/gui/app/templates/components/document/document-page.hbs index 7d5630ab..c30ff0bf 100644 --- a/gui/app/templates/components/document/document-page.hbs +++ b/gui/app/templates/components/document/document-page.hbs @@ -2,7 +2,7 @@ {{#if editMode}} {{document/document-editor document=document folder=folder page=page meta=meta onCancel=(action 'onCancelEdit') onAction=(action 'onSavePage')}} {{else}} - {{document/page-heading tagName=page.tagName document=document folder=folder page=page isEditor=isEditor tabMode=tabMode + {{document/page-heading tagName=page.tagName document=document folder=folder page=page permissions=permissions tabMode=tabMode onEdit=(action 'onEdit') onSavePageAsBlock=(action 'onSavePageAsBlock') onCopyPage=(action 'onCopyPage') onMovePage=(action 'onMovePage') onDeletePage=(action 'onDeletePage')}} {{section/base-renderer page=page}} diff --git a/gui/app/templates/components/document/document-tab.hbs b/gui/app/templates/components/document/document-tab.hbs index e9bdbb46..dd2a3052 100644 --- a/gui/app/templates/components/document/document-tab.hbs +++ b/gui/app/templates/components/document/document-tab.hbs @@ -1,5 +1,5 @@
- {{document/tab-heading tagName=page.tagName document=document folder=folder page=page isEditor=isEditor + {{document/tab-heading tagName=page.tagName document=document folder=folder page=page permissions=permissions onExpand=(action 'onExpand') onSavePageAsBlock=(action 'onSavePageAsBlock') onCopyPage=(action 'onCopyPage') onMovePage=(action 'onMovePage') onDeletePage=(action 'onDeletePage')}} {{#if expanded}} {{section/base-renderer page=page}} diff --git a/gui/app/templates/components/document/document-view.hbs b/gui/app/templates/components/document/document-view.hbs index 4c566ff2..5e6ef53c 100644 --- a/gui/app/templates/components/document/document-view.hbs +++ b/gui/app/templates/components/document/document-view.hbs @@ -2,7 +2,7 @@ {{#if hasPages}} {{#each pages key="id" as |page index|}} - {{#if isEditor}} + {{#if permissions.documentEdit}}
@@ -15,19 +15,19 @@
{{/if}} {{#if (is-equal page.pageType 'section')}} - {{#document/document-page document=document folder=folder page=page isEditor=isEditor toEdit=toEdit pageId=pageId + {{#document/document-page document=document folder=folder page=page permissions=permissions toEdit=toEdit pageId=pageId onSavePage=(action 'onSavePage') onSavePageAsBlock=(action 'onSavePageAsBlock') onCopyPage=(action 'onCopyPage') onMovePage=(action 'onMovePage') onDeletePage=(action 'onDeletePage')}} {{/document/document-page}} {{/if}} {{#if (is-equal page.pageType 'tab')}} - {{#document/document-tab document=document folder=folder page=page isEditor=isEditor pageId=pageId + {{#document/document-tab document=document folder=folder page=page permissions=permissions pageId=pageId onSavePage=(action 'onSavePage') onSavePageAsBlock=(action 'onSavePageAsBlock') onCopyPage=(action 'onCopyPage') onMovePage=(action 'onMovePage') onDeletePage=(action 'onDeletePage')}} {{/document/document-tab}} {{/if}} {{/each}} - {{#if isEditor}} + {{#if permissions.documentEdit}}
@@ -38,7 +38,7 @@
{{/if}} {{else}} - {{#if isEditor}} + {{#if permissions.documentEdit}}
diff --git a/gui/app/templates/components/document/page-heading.hbs b/gui/app/templates/components/document/page-heading.hbs index 2936780a..48f5ba8f 100644 --- a/gui/app/templates/components/document/page-heading.hbs +++ b/gui/app/templates/components/document/page-heading.hbs @@ -1,73 +1,89 @@
{{ page.title }}