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

Persist space permissions for groups and users

This commit is contained in:
sauls8t 2018-03-03 17:46:29 +00:00
parent 0d39f7251e
commit 7ccb3b4658
16 changed files with 320 additions and 157 deletions

View file

@ -1,4 +1,3 @@
gui/public/tinymce/**
gui/public/tinymce/
gui/public/tinymce
gui/public/tinymce

View file

@ -28,8 +28,10 @@ import (
"github.com/documize/community/domain"
"github.com/documize/community/domain/mail"
"github.com/documize/community/model/audit"
"github.com/documize/community/model/group"
"github.com/documize/community/model/permission"
"github.com/documize/community/model/space"
"github.com/documize/community/model/user"
)
// Handler contains the runtime information such as logging and database.
@ -122,52 +124,85 @@ func (h *Handler) SetSpacePermissions(w http.ResponseWriter, r *http.Request) {
hasEveryoneRole := false
roleCount := 0
// Permissions can be assigned to both groups and individual users.
// Pre-fetch users with group membership to help us work out
// if user belongs to a group with permissions.
groupMembers, err := h.Store.Group.GetMembers(ctx)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
for _, perm := range model.Permissions {
perm.OrgID = ctx.OrgID
perm.SpaceID = id
isGroup := perm.Who == permission.GroupPermission
groupRecords := []group.Record{}
if isGroup {
// get group records for just this group
groupRecords = group.FilterGroupRecords(groupMembers, perm.WhoID)
}
// Ensure the space owner always has access!
if perm.UserID == ctx.UserID {
if (!isGroup && perm.WhoID == ctx.UserID) ||
(isGroup && group.UserHasGroupMembership(groupMembers, perm.WhoID, ctx.UserID)) {
me = true
}
// Only persist if there is a role!
if permission.HasAnyPermission(perm) {
// identify publically shared spaces
if perm.UserID == "" {
perm.UserID = "0"
if perm.WhoID == "" {
perm.WhoID = user.EveryoneUserID
}
if perm.UserID == "0" {
if perm.WhoID == user.EveryoneUserID {
hasEveryoneRole = true
}
// Encode group/user permission and save to store.
r := permission.EncodeUserPermissions(perm)
roleCount++
for _, p := range r {
err = h.Store.Permission.AddPermission(ctx, p)
if err != nil {
h.Runtime.Log.Error("set permission", err)
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
}
}
// We send out space invitation emails to those users
// that have *just* been given permissions.
if _, isExisting := previousRoleUsers[perm.UserID]; !isExisting {
if _, isExisting := previousRoleUsers[perm.WhoID]; !isExisting {
// we skip 'everyone'
if perm.WhoID != user.EveryoneUserID {
whoToEmail := []string{}
// we skip 'everyone' (user id != empty string)
if perm.UserID != "0" && perm.UserID != "" {
existingUser, err := h.Store.User.Get(ctx, perm.UserID)
if err != nil {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
break
if isGroup {
// send email to each group member
for i := range groupRecords {
whoToEmail = append(whoToEmail, groupRecords[i].UserID)
}
} else {
// send email to individual user
whoToEmail = append(whoToEmail, perm.WhoID)
}
mailer := mail.Mailer{Runtime: h.Runtime, Store: h.Store, Context: ctx}
go mailer.ShareSpaceExistingUser(existingUser.Email, inviter.Fullname(), url, sp.Name, model.Message)
h.Runtime.Log.Info(fmt.Sprintf("%s is sharing space %s with existing user %s", inviter.Email, sp.Name, existingUser.Email))
for i := range whoToEmail {
existingUser, err := h.Store.User.Get(ctx, whoToEmail[i])
if err != nil {
h.Runtime.Log.Error(method, err)
continue
}
mailer := mail.Mailer{Runtime: h.Runtime, Store: h.Store, Context: ctx}
go mailer.ShareSpaceExistingUser(existingUser.Email, inviter.Fullname(), url, sp.Name, model.Message)
h.Runtime.Log.Info(fmt.Sprintf("%s is sharing space %s with existing user %s", inviter.Email, sp.Name, existingUser.Email))
}
}
}
}
@ -233,6 +268,7 @@ func (h *Handler) GetSpacePermissions(w http.ResponseWriter, r *http.Request) {
perms, err := h.Store.Permission.GetSpacePermissions(ctx, spaceID)
if err != nil && err != sql.ErrNoRows {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
@ -246,6 +282,40 @@ func (h *Handler) GetSpacePermissions(w http.ResponseWriter, r *http.Request) {
records = append(records, permission.DecodeUserPermissions(up))
}
// populate user/group name for thing that has permission record
groups, err := h.Store.Group.GetAll(ctx)
if err != nil && err != sql.ErrNoRows {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
for i := range records {
if records[i].Who == permission.GroupPermission {
for j := range groups {
if records[i].WhoID == groups[j].RefID {
records[i].Name = groups[j].Name
break
}
}
}
if records[i].Who == permission.UserPermission {
if records[i].WhoID == user.EveryoneUserID {
records[i].Name = "Everyone"
} else {
u, err := h.Store.User.Get(ctx, records[i].WhoID)
if err != nil {
h.Runtime.Log.Info(fmt.Sprintf("user not found %s", records[i].WhoID))
h.Runtime.Log.Error(method, err)
continue
}
records[i].Name = u.Fullname()
}
}
}
response.WriteJSON(w, records)
}
@ -261,7 +331,7 @@ func (h *Handler) GetUserSpacePermissions(w http.ResponseWriter, r *http.Request
}
perms, err := h.Store.Permission.GetUserSpacePermissions(ctx, spaceID)
if err != nil && err != sql.ErrNoRows {
if err != nil {
response.WriteServerError(w, method, err)
return
}
@ -464,11 +534,6 @@ func (h *Handler) SetDocumentPermissions(w http.ResponseWriter, r *http.Request)
return
}
// if !HasPermission(ctx, *h.Store, doc.LabelID, permission.SpaceManage, permission.SpaceOwner) {
// response.WriteForbiddenError(w)
// return
// }
defer streamutil.Close(r.Body)
body, err := ioutil.ReadAll(r.Body)
if err != nil {
@ -528,17 +593,38 @@ func (h *Handler) SetDocumentPermissions(w http.ResponseWriter, r *http.Request)
return
}
url := ctx.GetAppURL(fmt.Sprintf("s/%s/%s/d/%s/%s",
sp.RefID, stringutil.MakeSlug(sp.Name), doc.RefID, stringutil.MakeSlug(doc.Title)))
url := ctx.GetAppURL(fmt.Sprintf("s/%s/%s/d/%s/%s", sp.RefID, stringutil.MakeSlug(sp.Name), doc.RefID, stringutil.MakeSlug(doc.Title)))
// Permissions can be assigned to both groups and individual users.
// Pre-fetch users with group membership to help us work out
// if user belongs to a group with permissions.
groupMembers, err := h.Store.Group.GetMembers(ctx)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
for _, perm := range model {
perm.OrgID = ctx.OrgID
perm.DocumentID = id
isGroup := perm.Who == permission.GroupPermission
groupRecords := []group.Record{}
if isGroup {
// get group records for just this group
groupRecords = group.FilterGroupRecords(groupMembers, perm.WhoID)
}
// Only persist if there is a role!
if permission.HasAnyDocumentPermission(perm) {
r := permission.EncodeUserDocumentPermissions(perm)
if perm.WhoID == "" {
perm.WhoID = user.EveryoneUserID
}
r := permission.EncodeUserDocumentPermissions(perm)
for _, p := range r {
err = h.Store.Permission.AddPermission(ctx, p)
if err != nil {
@ -547,19 +633,32 @@ func (h *Handler) SetDocumentPermissions(w http.ResponseWriter, r *http.Request)
}
// Send email notification to users who have been given document approver role
if _, isExisting := previousRoleUsers[perm.UserID]; !isExisting {
if _, isExisting := previousRoleUsers[perm.WhoID]; !isExisting {
// we skip 'everyone' as it has no email address!
if perm.WhoID != user.EveryoneUserID && perm.DocumentRoleApprove {
whoToEmail := []string{}
// we skip 'everyone' (user id != empty string)
if perm.UserID != "0" && perm.UserID != "" && perm.DocumentRoleApprove {
existingUser, err := h.Store.User.Get(ctx, perm.UserID)
if err != nil {
response.WriteServerError(w, method, err)
break
if isGroup {
// send email to each group member
for i := range groupRecords {
whoToEmail = append(whoToEmail, groupRecords[i].UserID)
}
} else {
// send email to individual user
whoToEmail = append(whoToEmail, perm.WhoID)
}
mailer := mail.Mailer{Runtime: h.Runtime, Store: h.Store, Context: ctx}
go mailer.DocumentApprover(existingUser.Email, inviter.Fullname(), url, doc.Title)
h.Runtime.Log.Info(fmt.Sprintf("%s has made %s document approver for: %s", inviter.Email, existingUser.Email, doc.Title))
for i := range whoToEmail {
existingUser, err := h.Store.User.Get(ctx, whoToEmail[i])
if err != nil {
h.Runtime.Log.Error(method, err)
continue
}
mailer := mail.Mailer{Runtime: h.Runtime, Store: h.Store, Context: ctx}
go mailer.DocumentApprover(existingUser.Email, inviter.Fullname(), url, doc.Title)
h.Runtime.Log.Info(fmt.Sprintf("%s has made %s document approver for: %s", inviter.Email, existingUser.Email, doc.Title))
}
}
}
}

View file

@ -35,7 +35,7 @@ func (s Scope) AddPermission(ctx domain.RequestContext, r permission.Permission)
r.Created = time.Now().UTC()
_, err = ctx.Transaction.Exec("INSERT INTO permission (orgid, who, whoid, action, scope, location, refid, created) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
r.OrgID, r.Who, r.WhoID, string(r.Action), r.Scope, r.Location, r.RefID, r.Created)
r.OrgID, string(r.Who), r.WhoID, string(r.Action), string(r.Scope), string(r.Location), r.RefID, r.Created)
if err != nil {
err = errors.Wrap(err, "unable to execute insert permission")
@ -64,7 +64,8 @@ func (s Scope) AddPermissions(ctx domain.RequestContext, r permission.Permission
func (s Scope) GetUserSpacePermissions(ctx domain.RequestContext, spaceID string) (r []permission.Permission, err error) {
err = s.Runtime.Db.Select(&r, `
SELECT id, orgid, who, whoid, action, scope, location, refid
FROM permission WHERE orgid=? AND location='space' AND refid=? AND who='user' AND (whoid=? OR whoid='0')
FROM permission
WHERE orgid=? AND location='space' AND refid=? AND who='user' AND (whoid=? OR whoid='0')
UNION ALL
SELECT p.id, p.orgid, p.who, p.whoid, p.action, p.scope, p.location, p.refid
FROM permission p

View file

@ -203,7 +203,6 @@ export default Component.extend(AuthProvider, ModalMixin, {
group.set('isMember', false);
if (is.undefined(groupId) || is.undefined(userId)) {
console.log(groupId, userId);
return;
}
@ -218,7 +217,6 @@ export default Component.extend(AuthProvider, ModalMixin, {
group.set('isMember', true);
if (is.undefined(groupId) || is.undefined(userId)) {
console.log(groupId, userId);
return;
}

View file

@ -9,80 +9,78 @@
//
// https://documize.com
import { setProperties } from '@ember/object';
import Component from '@ember/component';
import { inject as service } from '@ember/service';
import { A } from "@ember/array"
import ModalMixin from '../../mixins/modal';
import Component from '@ember/component';
export default Component.extend(ModalMixin, {
folderService: service('folder'),
userService: service('user'),
appMeta: service(),
groupSvc: service('group'),
spaceSvc: service('folder'),
userSvc: service('user'),
appMeta: service(),
store: service(),
spacePermissions: null,
didReceiveAttrs() {
this.get('userService').getSpaceUsers(this.get('folder.id')).then((users) => {
this.set('users', users);
let spacePermissions = A([]);
let constants = this.get('constants');
// set up users
let folderPermissions = [];
// get groups
this.get('groupSvc').getAll().then((groups) => {
this.set('groups', groups);
users.forEach((user) => {
let u = {
orgId: this.get('folder.orgId'),
folderId: this.get('folder.id'),
userId: user.get('id'),
fullname: user.get('fullname'),
spaceView: false,
spaceManage: false,
spaceOwner: false,
documentAdd: false,
documentEdit: false,
documentDelete: false,
documentMove: false,
documentCopy: false,
documentTemplate: false,
documentApprove: false,
};
let data = this.get('store').normalize('space-permission', u)
folderPermissions.pushObject(this.get('store').push(data));
groups.forEach((g) => {
let pr = this.permissionRecord(constants.WhoType.Group, g.get('id'), g.get('name'));
spacePermissions.pushObject(pr);
});
// set up Everyone user
let u = {
orgId: this.get('folder.orgId'),
folderId: this.get('folder.id'),
userId: '0',
fullname: ' Everyone',
spaceView: false,
spaceManage: false,
spaceOwner: false,
documentAdd: false,
documentEdit: false,
documentDelete: false,
documentMove: false,
documentCopy: false,
documentTemplate: false,
documentApprove: false,
};
let data = this.get('store').normalize('space-permission', u)
folderPermissions.pushObject(this.get('store').push(data));
this.get('folderService').getPermissions(this.get('folder.id')).then((permissions) => {
permissions.forEach((permission, index) => { // eslint-disable-line no-unused-vars
let record = folderPermissions.findBy('userId', permission.get('userId'));
if (is.not.undefined(record)) {
record = setProperties(record, permission);
// get space permissions
this.get('spaceSvc').getPermissions(this.get('folder.id')).then((permissions) => {
permissions.forEach((perm, index) => { // eslint-disable-line no-unused-vars
// is this permission for group or user?
if (perm.get('who') === constants.WhoType.Group) {
// group permission
spacePermissions.forEach((sp) => {
if (sp.get('whoId') == perm.get('whoId')) {
sp.setProperties(perm);
}
});
} else {
// user permission
spacePermissions.pushObject(perm);
}
});
this.set('permissions', folderPermissions.sortBy('fullname'));
this.set('spacePermissions', spacePermissions.sortBy('who', 'name'));
});
});
},
permissionRecord(who, whoId, name) {
let raw = {
id: whoId,
orgId: this.get('folder.orgId'),
folderId: this.get('folder.id'),
whoId: whoId,
who: who,
name: name,
spaceView: false,
spaceManage: false,
spaceOwner: false,
documentAdd: false,
documentEdit: false,
documentDelete: false,
documentMove: false,
documentCopy: false,
documentTemplate: false,
documentApprove: false,
};
let rec = this.get('store').normalize('space-permission', raw);
return this.get('store').push(rec);
},
getDefaultInvitationMessage() {
return "Hey there, I am sharing the " + this.get('folder.name') + " space (in " + this.get("appMeta.title") + ") with you so we can both collaborate on documents.";
},
@ -90,12 +88,13 @@ export default Component.extend(ModalMixin, {
actions: {
setPermissions() {
let message = this.getDefaultInvitationMessage();
let permissions = this.get('permissions');
let permissions = this.get('spacePermissions');
let folder = this.get('folder');
let payload = { Message: message, Permissions: permissions };
let constants = this.get('constants');
let hasEveryone = _.find(permissions, function (permission) {
return permission.get('userId') === "0" &&
let hasEveryone = _.find(permissions, (permission) => {
return permission.get('whoId') === constants.EveryoneUserId &&
(permission.get('spaceView') || permission.get('documentAdd') || permission.get('documentEdit') || permission.get('documentDelete') ||
permission.get('documentMove') || permission.get('documentCopy') || permission.get('documentTemplate') || permission.get('documentApprove'));
});
@ -103,7 +102,7 @@ export default Component.extend(ModalMixin, {
// see if more than oen user is granted access to space (excluding everyone)
let roleCount = 0;
permissions.forEach((permission) => {
if (permission.get('userId') !== "0" &&
if (permission.get('whoId') !== constants.EveryoneUserId &&
(permission.get('spaceView') || permission.get('documentAdd') || permission.get('documentEdit') || permission.get('documentDelete') ||
permission.get('documentMove') || permission.get('documentCopy') || permission.get('documentTemplate') || permission.get('documentApprove'))) {
roleCount += 1;
@ -120,7 +119,7 @@ export default Component.extend(ModalMixin, {
}
}
this.get('folderService').savePermissions(folder.get('id'), payload).then(() => {
this.get('spaceSvc').savePermissions(folder.get('id'), payload).then(() => {
this.modalClose('#space-permission-modal');
});
}

View file

@ -10,7 +10,6 @@
// https://documize.com
import $ from 'jquery';
import Component from '@ember/component';
import { computed } from '@ember/object';
import { schedule } from '@ember/runloop';
import { inject as service } from '@ember/service';
@ -18,6 +17,7 @@ import TooltipMixin from '../../mixins/tooltip';
import ModalMixin from '../../mixins/modal';
import AuthMixin from '../../mixins/auth';
import stringUtil from '../../utils/string';
import Component from '@ember/component';
export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, {
spaceService: service('folder'),

View file

@ -11,6 +11,9 @@
import EmberObject from "@ember/object";
// access like so:
// let constants = this.get('constants');
let constants = EmberObject.extend({
// Document
ProtectionType: { // eslint-disable-line ember/avoid-leaking-state-in-ember-objects
@ -48,7 +51,15 @@ let constants = EmberObject.extend({
PageType: { // eslint-disable-line ember/avoid-leaking-state-in-ember-objects
Tab: 'tab',
Section: 'section'
}
},
// Who a permission record relates to
WhoType: { // eslint-disable-line ember/avoid-leaking-state-in-ember-objects
User: 'user',
Group: 'role'
},
EveryoneUserId: "0"
});
export default { constants }

View file

@ -11,14 +11,12 @@
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
// import { belongsTo, hasMany } from 'ember-data/relationships';
export default Model.extend({
orgId: attr('string'),
folderId: attr('string'),
userId: attr('string'),
fullname: attr('string'), // client-side usage only, not from API
whoId: attr('string'),
who: attr('string'),
spaceView: attr('boolean'),
spaceManage: attr('boolean'),
spaceOwner: attr('boolean'),
@ -28,5 +26,6 @@ export default Model.extend({
documentMove: attr('boolean'),
documentCopy: attr('boolean'),
documentTemplate: attr('boolean'),
documentApprove: attr('boolean')
documentApprove: attr('boolean'),
name: attr('string') // read-only
});

View file

@ -4,7 +4,7 @@ export default ApplicationSerializer.extend({
normalize(modelClass, resourceHash) {
return {
data: {
id: resourceHash.userId ? resourceHash.userId : 0,
id: resourceHash.whoId ? resourceHash.whoId : 0,
type: modelClass.modelName,
attributes: resourceHash
}

View file

@ -20,6 +20,7 @@ export default BaseService.extend({
localStorage: service(),
store: service(),
currentFolder: null,
permissions: null,
init() {
this._super(...arguments);

View file

@ -27,38 +27,50 @@
</tr>
</thead>
<tbody>
{{#each permissions as |permission|}}
{{#each spacePermissions as |permission|}}
<tr>
<td>{{permission.fullname}} {{if (eq permission.userId session.user.id) '(you)'}}</td>
<td>
{{input type="checkbox" id=(concat 'space-role-view-' permission.userId) checked=permission.spaceView}}
{{#if (eq permission.who "role")}}
<span class="button-icon-gray button-icon-small align-middle">
<i class="material-icons">people</i>
</span>
&nbsp;<b>{{permission.name}}</b>
{{else}}
<span class="button-icon-gray button-icon-small align-middle">
<i class="material-icons">person</i>
</span>
&nbsp;<b>{{permission.name}}</b> {{if (eq permission.whoId session.user.id) '(you)'}}
{{/if}}
</td>
<td>
{{input type="checkbox" id=(concat 'space-role-manage-' permission.userId) checked=permission.spaceManage}}
{{input type="checkbox" id=(concat 'space-role-view-' permission.whoId) checked=permission.spaceView}}
</td>
<td>
{{input type="checkbox" id=(concat 'space-role-owner-' permission.userId) checked=permission.spaceOwner}}
{{input type="checkbox" id=(concat 'space-role-manage-' permission.whoId) checked=permission.spaceManage}}
</td>
<td>
{{input type="checkbox" id=(concat 'doc-role-add-' permission.userId) checked=permission.documentAdd}}
{{input type="checkbox" id=(concat 'space-role-owner-' permission.whoId) checked=permission.spaceOwner}}
</td>
<td>
{{input type="checkbox" id=(concat 'doc-role-edit-' permission.userId) checked=permission.documentEdit}}
{{input type="checkbox" id=(concat 'doc-role-add-' permission.whoId) checked=permission.documentAdd}}
</td>
<td>
{{input type="checkbox" id=(concat 'doc-role-delete-' permission.userId) checked=permission.documentDelete}}
{{input type="checkbox" id=(concat 'doc-role-edit-' permission.whoId) checked=permission.documentEdit}}
</td>
<td>
{{input type="checkbox" id=(concat 'doc-role-move-' permission.userId) checked=permission.documentMove}}
{{input type="checkbox" id=(concat 'doc-role-delete-' permission.whoId) checked=permission.documentDelete}}
</td>
<td>
{{input type="checkbox" id=(concat 'doc-role-copy-' permission.userId) checked=permission.documentCopy}}
{{input type="checkbox" id=(concat 'doc-role-move-' permission.whoId) checked=permission.documentMove}}
</td>
<td>
{{input type="checkbox" id=(concat 'doc-role-template-' permission.userId) checked=permission.documentTemplate}}
{{input type="checkbox" id=(concat 'doc-role-copy-' permission.whoId) checked=permission.documentCopy}}
</td>
<td>
{{input type="checkbox" id=(concat 'doc-role-approve-' permission.userId) checked=permission.documentApprove}}
{{input type="checkbox" id=(concat 'doc-role-template-' permission.whoId) checked=permission.documentTemplate}}
</td>
<td>
{{input type="checkbox" id=(concat 'doc-role-approve-' permission.whoId) checked=permission.documentApprove}}
</td>
</tr>
{{/each}}

View file

@ -41,3 +41,27 @@ type Record struct {
Name string `json:"name"`
Purpose string `json:"purpose"`
}
// UserHasGroupMembership returns true if user belongs to specified group.
func UserHasGroupMembership(r []Record, groupID, userID string) bool {
for i := range r {
if r[i].RoleID == groupID && r[i].UserID == userID {
return true
}
}
return false
}
// FilterGroupRecords returns only those records matching group ID.
func FilterGroupRecords(r []Record, groupID string) (m []Record) {
m = []Record{}
for i := range r {
if r[i].RoleID == groupID {
m = append(m, r[i])
}
}
return
}

View file

@ -15,11 +15,12 @@ package permission
// This data structure is made from database permission records for the document,
// and it is designed to be sent to HTTP clients (web, mobile).
type DocumentRecord struct {
OrgID string `json:"orgId"`
DocumentID string `json:"documentId"`
UserID string `json:"userId"`
DocumentRoleEdit bool `json:"documentRoleEdit"`
DocumentRoleApprove bool `json:"documentRoleApprove"`
OrgID string `json:"orgId"`
DocumentID string `json:"documentId"`
WhoID string `json:"whoId"`
Who WhoType `json:"who"`
DocumentRoleEdit bool `json:"documentRoleEdit"`
DocumentRoleApprove bool `json:"documentRoleApprove"`
}
// DecodeUserDocumentPermissions returns a flat, usable permission summary record
@ -29,7 +30,8 @@ func DecodeUserDocumentPermissions(perm []Permission) (r DocumentRecord) {
if len(perm) > 0 {
r.OrgID = perm[0].OrgID
r.UserID = perm[0].WhoID
r.WhoID = perm[0].WhoID
r.Who = perm[0].Who
r.DocumentID = perm[0].RefID
}
@ -67,8 +69,8 @@ func HasAnyDocumentPermission(p DocumentRecord) bool {
func EncodeDocumentRecord(r DocumentRecord, a Action) (p Permission) {
p = Permission{}
p.OrgID = r.OrgID
p.Who = UserPermission
p.WhoID = r.UserID
p.WhoID = r.WhoID
p.Who = r.Who
p.Location = LocationDocument
p.RefID = r.DocumentID
p.Action = a

View file

@ -15,19 +15,21 @@ package permission
// This data structure is made from database permission records for the space,
// and it is designed to be sent to HTTP clients (web, mobile).
type Record struct {
OrgID string `json:"orgId"`
SpaceID string `json:"folderId"`
UserID string `json:"userId"`
SpaceView bool `json:"spaceView"`
SpaceManage bool `json:"spaceManage"`
SpaceOwner bool `json:"spaceOwner"`
DocumentAdd bool `json:"documentAdd"`
DocumentEdit bool `json:"documentEdit"`
DocumentDelete bool `json:"documentDelete"`
DocumentMove bool `json:"documentMove"`
DocumentCopy bool `json:"documentCopy"`
DocumentTemplate bool `json:"documentTemplate"`
DocumentApprove bool `json:"documentApprove"`
OrgID string `json:"orgId"`
SpaceID string `json:"folderId"`
WhoID string `json:"whoId"`
Who WhoType `json:"who"`
SpaceView bool `json:"spaceView"`
SpaceManage bool `json:"spaceManage"`
SpaceOwner bool `json:"spaceOwner"`
DocumentAdd bool `json:"documentAdd"`
DocumentEdit bool `json:"documentEdit"`
DocumentDelete bool `json:"documentDelete"`
DocumentMove bool `json:"documentMove"`
DocumentCopy bool `json:"documentCopy"`
DocumentTemplate bool `json:"documentTemplate"`
DocumentApprove bool `json:"documentApprove"`
Name string `json:"name"` // read-only, user or group name
}
// DecodeUserPermissions returns a flat, usable permission summary record
@ -37,7 +39,8 @@ func DecodeUserPermissions(perm []Permission) (r Record) {
if len(perm) > 0 {
r.OrgID = perm[0].OrgID
r.UserID = perm[0].WhoID
r.WhoID = perm[0].WhoID
r.Who = perm[0].Who
r.SpaceID = perm[0].RefID
}
@ -118,8 +121,8 @@ func HasAnyPermission(p Record) bool {
func EncodeRecord(r Record, a Action) (p Permission) {
p = Permission{}
p.OrgID = r.OrgID
p.Who = UserPermission
p.WhoID = r.UserID
p.Who = r.Who
p.WhoID = r.WhoID
p.Location = LocationSpace
p.RefID = r.SpaceID
p.Action = a

View file

@ -71,3 +71,8 @@ func Exists(users []User, userID string) bool {
return false
}
const (
// EveryoneUserID provides a shortcut to state "all authenticated users".
EveryoneUserID string = "0"
)

View file

@ -91,9 +91,9 @@ func RegisterEndpoints(rt *env.Runtime, s *domain.Store) {
Add(rt, RoutePrefixPrivate, "documents/{documentID}", []string{"GET", "OPTIONS"}, nil, document.Get)
Add(rt, RoutePrefixPrivate, "documents/{documentID}", []string{"PUT", "OPTIONS"}, nil, document.Update)
Add(rt, RoutePrefixPrivate, "documents/{documentID}", []string{"DELETE", "OPTIONS"}, nil, document.Delete)
Add(rt, RoutePrefixPrivate, "documents/{documentID}/permissions", []string{"GET", "OPTIONS"}, nil, permission.GetDocumentPermissions)
Add(rt, RoutePrefixPrivate, "documents/{documentID}/permissions", []string{"PUT", "OPTIONS"}, nil, permission.SetDocumentPermissions)
Add(rt, RoutePrefixPrivate, "documents/{documentID}/permissions/user", []string{"GET", "OPTIONS"}, nil, permission.GetUserDocumentPermissions)
// Add(rt, RoutePrefixPrivate, "documents/{documentID}/permissions", []string{"GET", "OPTIONS"}, nil, permission.GetDocumentPermissions)
// Add(rt, RoutePrefixPrivate, "documents/{documentID}/permissions", []string{"PUT", "OPTIONS"}, nil, permission.SetDocumentPermissions)
// Add(rt, RoutePrefixPrivate, "documents/{documentID}/permissions/user", []string{"GET", "OPTIONS"}, nil, permission.GetUserDocumentPermissions)
Add(rt, RoutePrefixPrivate, "documents/{documentID}/pages/level", []string{"POST", "OPTIONS"}, nil, page.ChangePageLevel)
Add(rt, RoutePrefixPrivate, "documents/{documentID}/pages/sequence", []string{"POST", "OPTIONS"}, nil, page.ChangePageSequence)
@ -119,9 +119,9 @@ func RegisterEndpoints(rt *env.Runtime, s *domain.Store) {
Add(rt, RoutePrefixPrivate, "space/{spaceID}", []string{"DELETE", "OPTIONS"}, nil, space.Delete)
Add(rt, RoutePrefixPrivate, "space/{spaceID}/move/{moveToId}", []string{"DELETE", "OPTIONS"}, nil, space.Remove)
Add(rt, RoutePrefixPrivate, "space/{spaceID}/permissions", []string{"PUT", "OPTIONS"}, nil, permission.SetSpacePermissions)
Add(rt, RoutePrefixPrivate, "space/{spaceID}/permissions/user", []string{"GET", "OPTIONS"}, nil, permission.GetUserSpacePermissions)
Add(rt, RoutePrefixPrivate, "space/{spaceID}/permissions", []string{"GET", "OPTIONS"}, nil, permission.GetSpacePermissions)
// Add(rt, RoutePrefixPrivate, "space/{spaceID}/permissions", []string{"PUT", "OPTIONS"}, nil, permission.SetSpacePermissions)
// Add(rt, RoutePrefixPrivate, "space/{spaceID}/permissions/user", []string{"GET", "OPTIONS"}, nil, permission.GetUserSpacePermissions)
// Add(rt, RoutePrefixPrivate, "space/{spaceID}/permissions", []string{"GET", "OPTIONS"}, nil, permission.GetSpacePermissions)
Add(rt, RoutePrefixPrivate, "space/{spaceID}/invitation", []string{"POST", "OPTIONS"}, nil, space.Invite)
Add(rt, RoutePrefixPrivate, "space/manage", []string{"GET", "OPTIONS"}, nil, space.GetAll)
Add(rt, RoutePrefixPrivate, "space/{spaceID}", []string{"GET", "OPTIONS"}, nil, space.Get)
@ -131,11 +131,11 @@ func RegisterEndpoints(rt *env.Runtime, s *domain.Store) {
Add(rt, RoutePrefixPrivate, "category/space/{spaceID}/summary", []string{"GET", "OPTIONS"}, nil, category.GetSummary)
Add(rt, RoutePrefixPrivate, "category/document/{documentID}", []string{"GET", "OPTIONS"}, nil, category.GetDocumentCategoryMembership)
Add(rt, RoutePrefixPrivate, "category/{categoryID}/permission", []string{"PUT", "OPTIONS"}, nil, permission.SetCategoryPermissions)
Add(rt, RoutePrefixPrivate, "category/{categoryID}/permission", []string{"GET", "OPTIONS"}, nil, permission.GetCategoryPermissions)
// Add(rt, RoutePrefixPrivate, "category/{categoryID}/permission", []string{"PUT", "OPTIONS"}, nil, permission.SetCategoryPermissions)
// Add(rt, RoutePrefixPrivate, "category/{categoryID}/permission", []string{"GET", "OPTIONS"}, nil, permission.GetCategoryPermissions)
Add(rt, RoutePrefixPrivate, "category/space/{spaceID}", []string{"GET", "OPTIONS"}, []string{"filter", "all"}, category.GetAll)
Add(rt, RoutePrefixPrivate, "category/space/{spaceID}", []string{"GET", "OPTIONS"}, nil, category.Get)
Add(rt, RoutePrefixPrivate, "category/{categoryID}/user", []string{"GET", "OPTIONS"}, nil, permission.GetCategoryViewers)
// Add(rt, RoutePrefixPrivate, "category/{categoryID}/user", []string{"GET", "OPTIONS"}, nil, permission.GetCategoryViewers)
Add(rt, RoutePrefixPrivate, "category/member/space/{spaceID}", []string{"GET", "OPTIONS"}, nil, category.GetSpaceCategoryMembers)
Add(rt, RoutePrefixPrivate, "category/member", []string{"POST", "OPTIONS"}, nil, category.SetDocumentCategoryMembership)
Add(rt, RoutePrefixPrivate, "category/{categoryID}", []string{"PUT", "OPTIONS"}, nil, category.Update)
@ -192,6 +192,16 @@ func RegisterEndpoints(rt *env.Runtime, s *domain.Store) {
Add(rt, RoutePrefixPrivate, "group/{groupID}/join/{userID}", []string{"POST", "OPTIONS"}, nil, group.JoinGroup)
Add(rt, RoutePrefixPrivate, "group/{groupID}/leave/{userID}", []string{"DELETE", "OPTIONS"}, nil, group.LeaveGroup)
Add(rt, RoutePrefixPrivate, "documents/{documentID}/permissions", []string{"GET", "OPTIONS"}, nil, permission.GetDocumentPermissions)
Add(rt, RoutePrefixPrivate, "documents/{documentID}/permissions", []string{"PUT", "OPTIONS"}, nil, permission.SetDocumentPermissions)
Add(rt, RoutePrefixPrivate, "documents/{documentID}/permissions/user", []string{"GET", "OPTIONS"}, nil, permission.GetUserDocumentPermissions)
Add(rt, RoutePrefixPrivate, "space/{spaceID}/permissions", []string{"PUT", "OPTIONS"}, nil, permission.SetSpacePermissions)
Add(rt, RoutePrefixPrivate, "space/{spaceID}/permissions/user", []string{"GET", "OPTIONS"}, nil, permission.GetUserSpacePermissions)
Add(rt, RoutePrefixPrivate, "space/{spaceID}/permissions", []string{"GET", "OPTIONS"}, nil, permission.GetSpacePermissions)
Add(rt, RoutePrefixPrivate, "category/{categoryID}/permission", []string{"PUT", "OPTIONS"}, nil, permission.SetCategoryPermissions)
Add(rt, RoutePrefixPrivate, "category/{categoryID}/permission", []string{"GET", "OPTIONS"}, nil, permission.GetCategoryPermissions)
Add(rt, RoutePrefixPrivate, "category/{categoryID}/user", []string{"GET", "OPTIONS"}, nil, permission.GetCategoryViewers)
// fetch methods exist to speed up UI rendering by returning data in bulk
Add(rt, RoutePrefixPrivate, "fetch/category/space/{spaceID}", []string{"GET", "OPTIONS"}, nil, category.FetchSpaceData)
Add(rt, RoutePrefixPrivate, "fetch/document/{documentID}", []string{"GET", "OPTIONS"}, nil, document.FetchDocumentData)