1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-21 06:09:42 +02:00

persist permissions

WIP
This commit is contained in:
Harvey Kandola 2017-09-15 11:08:05 +01:00
parent 5f7c6d211f
commit ef285c91de
13 changed files with 764 additions and 829 deletions

View file

@ -161,7 +161,7 @@ func setupAccount(rt *env.Runtime, completion onboardRequest, serial string) (er
return err
}
// Set up default labels for main collection.
// create space
labelID := uniqueid.Generate()
sql = fmt.Sprintf("insert into label (refid, orgid, label, type, userid) values (\"%s\", \"%s\", \"My Project\", 2, \"%s\")", labelID, orgID, userID)
_, err = runSQL(rt, sql)
@ -170,12 +170,14 @@ func setupAccount(rt *env.Runtime, completion onboardRequest, serial string) (er
rt.Log.Error("insert into label failed", err)
}
labelRoleID := uniqueid.Generate()
sql = fmt.Sprintf("insert into labelrole (refid, labelid, orgid, userid, canview, canedit) values (\"%s\", \"%s\", \"%s\", \"%s\", 1, 1)", labelRoleID, labelID, orgID, userID)
_, err = runSQL(rt, sql)
if err != nil {
rt.Log.Error("insert into labelrole failed", err)
// assign permissions to space
perms := []string{"view", "manage", "own", "doc-add", "doc-edit", "doc-delete", "doc-move", "doc-copy", "doc-template"}
for _, p := range perms {
sql = fmt.Sprintf("insert into permissions (orgid, who, whoid, action, scope, location, refid) values (\"%s\", 'who', \"%s\", \"%s\", 'object', 'space', \"%s\")", orgID, userID, p, labelID)
_, err = runSQL(rt, sql)
if err != nil {
rt.Log.Error("insert into permission failed", err)
}
}
return

View file

@ -36,7 +36,6 @@ import (
"github.com/documize/community/model/doc"
"github.com/documize/community/model/page"
"github.com/documize/community/model/space"
"github.com/documize/community/model/user"
uuid "github.com/nu7hatch/gouuid"
)
@ -553,7 +552,7 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
sp, err := h.Store.Space.Get(ctx, id)
if err != nil {
response.WriteNotFoundError(w, method, "No such space")
response.WriteNotFoundError(w, method, "space not found")
return
}
@ -570,7 +569,7 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
return
}
var model = space.RolesModel{}
var model = space.PermissionsModel{}
err = json.Unmarshal(body, &model)
if err != nil {
response.WriteServerError(w, method, err)
@ -597,7 +596,6 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
// Store all previous roles as map for easy querying
previousRoleUsers := make(map[string]bool)
for _, v := range previousRoles {
previousRoleUsers[v.WhoID] = true
}
@ -628,42 +626,45 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
for _, perm := range model.Permissions {
perm.OrgID = ctx.OrgID
perm.RefID = id
perm.SpaceID = id
// Ensure the space owner always has access!
if perm.WhoID == ctx.UserID {
if perm.UserID == ctx.UserID {
me = true
}
if len(perm.WhoID) == 0 {
if len(perm.UserID) == 0 {
hasEveryoneRole = true
}
// Only persist if there is a role!
if perm.Action == "TBC" {
err = h.Store.Space.AddPermission(ctx, perm)
if err != nil {
h.Runtime.Log.Error("add role", err)
}
if space.HasAnyPermission(perm) {
r := space.EncodeUserPermissions(perm)
roleCount++
for _, p := range r {
err = h.Store.Space.AddPermission(ctx, p)
if err != nil {
h.Runtime.Log.Error("set permission", err)
}
roleCount++
}
// We send out space invitation emails to those users
// that have *just* been given permissions.
if _, isExisting := previousRoleUsers[perm.WhoID]; !isExisting {
if _, isExisting := previousRoleUsers[perm.UserID]; !isExisting {
// we skip 'everyone' (user id != empty string)
if len(perm.WhoID) > 0 {
var existingUser user.User
existingUser, err = h.Store.User.Get(ctx, perm.WhoID)
if err == nil {
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))
} else {
if len(perm.UserID) > 0 {
existingUser, err := h.Store.User.Get(ctx, perm.UserID)
if err != nil {
response.WriteServerError(w, method, err)
break
}
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))
}
}
}
@ -680,7 +681,7 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
perm.RefID = id
perm.Action = "" // we send array for actions below
err = h.Store.Space.AddPermission(ctx, perm)
err = h.Store.Space.AddPermissions(ctx, perm, space.SpaceView, space.SpaceManage)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)

View file

@ -90,26 +90,25 @@ func (s Scope) PublicSpaces(ctx domain.RequestContext, orgID string) (sp []space
// Also handles which spaces can be seen by anonymous users.
func (s Scope) GetAll(ctx domain.RequestContext) (sp []space.Space, err error) {
sql := `
(SELECT id,refid,label as name,orgid,userid,type,created,revised from label WHERE orgid=? AND type=2 AND userid=?)
UNION ALL
(SELECT id,refid,label as name,orgid,userid,type,created,revised 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 id,refid,label as name,orgid,userid,type,created,revised 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)))
SELECT id,refid,label as name,orgid,userid,type,created,revised 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 name`
err = s.Runtime.Db.Select(&sp, sql,
ctx.OrgID,
ctx.OrgID,
ctx.OrgID,
ctx.UserID,
ctx.OrgID,
ctx.OrgID,
ctx.OrgID,
ctx.OrgID,
ctx.UserID)
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("Unable to execute select labels for org %s", ctx.OrgID))
err = errors.Wrap(err, fmt.Sprintf("failed space.GetAll org %s", ctx.OrgID))
return
}
@ -137,25 +136,6 @@ func (s Scope) Update(ctx domain.RequestContext, sp space.Space) (err error) {
return
}
// ChangeOwner transfer space ownership.
func (s Scope) ChangeOwner(ctx domain.RequestContext, currentOwner, newOwner string) (err error) {
stmt, err := ctx.Transaction.Preparex("UPDATE label SET userid=? WHERE userid=? AND orgid=?")
defer streamutil.Close(stmt)
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("unable to prepare change space owner for %s", currentOwner))
return
}
_, err = stmt.Exec(newOwner, currentOwner, ctx.OrgID)
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("unable to execute change space owner for %s", currentOwner))
return
}
return
}
// Viewers returns the list of people who can see shared spaces.
func (s Scope) Viewers(ctx domain.RequestContext) (v []space.Viewer, err error) {
sql := `
@ -184,11 +164,11 @@ func (s Scope) Delete(ctx domain.RequestContext, id string) (rows int64, err err
return b.DeleteConstrained(ctx.Transaction, "label", ctx.OrgID, id)
}
// AddPermission inserts the given record into the labelrole database table.
// AddPermission inserts the given record into the permisssion table.
func (s Scope) AddPermission(ctx domain.RequestContext, r space.Permission) (err error) {
r.Created = time.Now().UTC()
stmt, err := ctx.Transaction.Preparex("INSERT INTO labelrole (orgid, who, whoid, action, scope, location, refid, created) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
stmt, err := ctx.Transaction.Preparex("INSERT INTO permission (orgid, who, whoid, action, scope, location, refid, created) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
defer streamutil.Close(stmt)
if err != nil {
@ -196,7 +176,7 @@ func (s Scope) AddPermission(ctx domain.RequestContext, r space.Permission) (err
return
}
_, err = stmt.Exec(r.OrgID, r.Who, r.WhoID, r.Action, r.Scope, r.Location, r.RefID, r.Created)
_, err = stmt.Exec(r.OrgID, r.Who, r.WhoID, string(r.Action), r.Scope, r.Location, r.RefID, r.Created)
if err != nil {
err = errors.Wrap(err, "unable to execute insert for space permission")
return
@ -279,3 +259,13 @@ func (s Scope) DeleteUserPermissions(ctx domain.RequestContext, spaceID, userID
return b.DeleteWhere(ctx.Transaction, sql)
}
// DeleteAllUserPermissions removes all roles for the specified user, for the specified space.
func (s Scope) DeleteAllUserPermissions(ctx domain.RequestContext, userID string) (rows int64, err error) {
b := mysql.BaseQuery{}
sql := fmt.Sprintf("DELETE FROM permission WHERE orgid='%s' AND who='user' AND whoid='%s'",
ctx.OrgID, userID)
return b.DeleteWhere(ctx.Transaction, sql)
}

View file

@ -53,7 +53,6 @@ type SpaceStorer interface {
PublicSpaces(ctx RequestContext, orgID string) (sp []space.Space, err error)
GetAll(ctx RequestContext) (sp []space.Space, err error)
Update(ctx RequestContext, sp space.Space) (err error)
ChangeOwner(ctx RequestContext, currentOwner, newOwner string) (err error)
Viewers(ctx RequestContext) (v []space.Viewer, err error)
Delete(ctx RequestContext, id string) (rows int64, err error)
@ -61,8 +60,9 @@ type SpaceStorer interface {
AddPermissions(ctx RequestContext, r space.Permission, actions ...space.PermissionAction) (err error)
GetUserPermissions(ctx RequestContext, spaceID string) (r []space.Permission, err error)
GetPermissions(ctx RequestContext, spaceID string) (r []space.Permission, err error)
DeleteUserPermissions(ctx RequestContext, spaceID, userID string) (rows int64, err error)
DeletePermissions(ctx RequestContext, spaceID string) (rows int64, err error)
DeleteUserPermissions(ctx RequestContext, spaceID, userID string) (rows int64, err error)
DeleteAllUserPermissions(ctx RequestContext, userID string) (rows int64, err error)
}
// UserStorer defines required methods for user management

View file

@ -377,7 +377,8 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
return
}
err = h.Store.Space.ChangeOwner(ctx, userID, ctx.UserID)
// remove all associated roles for this user
_, err = h.Store.Space.DeleteAllUserPermissions(ctx, userID)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)

File diff suppressed because one or more lines are too long

View file

@ -76,9 +76,9 @@ export default Ember.Component.extend(NotifierMixin, {
this.get('folderService').getPermissions(this.get('folder.id')).then((permissions) => {
permissions.forEach((permission, index) => { // eslint-disable-line no-unused-vars
let user = folderPermissions.findBy('userId', permission.get('userId'));
if (is.not.undefined(user)) {
Ember.setProperties(user, permission);
let record = folderPermissions.findBy('userId', permission.get('userId'));
if (is.not.undefined(record)) {
record = Ember.setProperties(record, permission);
}
});
@ -88,50 +88,40 @@ export default Ember.Component.extend(NotifierMixin, {
},
getDefaultInvitationMessage() {
return "Hey there, I am sharing the " + this.get('folder.name') + " space (in " + this.get("appMeta.title") + ") with you so we can both access the same documents.";
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.";
},
actions: {
setPermissions() {
let message = this.getDefaultInvitationMessage();
// let folder = this.get('folder');
let permissions = this.get('permissions');
let folder = this.get('folder');
let payload = { Message: message, Permissions: permissions };
permissions.forEach((permission, index) => { // eslint-disable-line no-unused-vars
Ember.set(permission, 'spaceView', $("#space-role-view-" + permission.get('userId')).prop('checked'));
Ember.set(permission, 'spaceManage', $("#space-role-manage-" + permission.get('userId')).prop('checked'));
Ember.set(permission, 'spaceOwner', $("#space-role-owner-" + permission.get('userId')).prop('checked'));
Ember.set(permission, 'documentAdd', $("#doc-role-add-" + permission.get('userId')).prop('checked'));
Ember.set(permission, 'documentEdit', $("#doc-role-edit-" + permission.get('userId')).prop('checked'));
Ember.set(permission, 'documentDelete', $("#doc-role-delete-" + permission.get('userId')).prop('checked'));
Ember.set(permission, 'documentMove', $("#doc-role-move-" + permission.get('userId')).prop('checked'));
Ember.set(permission, 'documentCopy', $("#doc-role-copy-" + permission.get('userId')).prop('checked'));
Ember.set(permission, 'documentTemplate', $("#doc-role-template-" + permission.get('userId')).prop('checked'));
let hasEveryone = _.find(permissions, function (permission) {
return permission.get('userId') === "" &&
(permission.get('spaceView') || permission.get('documentAdd') || permission.get('documentEdit') || permission.get('documentDelete') ||
permission.get('documentMove') || permission.get('documentCopy') || permission.get('documentTemplate'));
});
let payload = { Message: message, Permissions: permissions };
console.log(payload);
this.get('folderService').savePermissions(folder.get('id'), payload).then(() => {
this.showNotification('Saved permissions');
});
// this.get('folderService').savePermissions(folder.get('id'), payload).then(() => {
// this.showNotification('Saved permissions');
// });
if (is.not.undefined(hasEveryone)) {
folder.markAsPublic();
this.showNotification('Marked space as public');
} else {
if (permissions.length > 1) {
folder.markAsRestricted();
this.showNotification('Marked space as protected');
} else {
folder.markAsPrivate();
this.showNotification('Marked space as private');
}
}
// var hasEveryone = _.find(data, function (permission) {
// return permission.userId === "" && (permission.canView || permission.canEdit);
// });
// if (is.not.undefined(hasEveryone)) {
// folder.markAsPublic();
// } else {
// if (data.length > 1) {
// folder.markAsRestricted();
// } else {
// folder.markAsPrivate();
// }
// }
// this.get('folderService').save(folder).then(function () {
// });
// this.get('folderService').save(folder).then(function () {});
}
}
});

View file

@ -1,22 +0,0 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { belongsTo } from 'ember-data/relationships';
export default Model.extend({
orgId: attr('string'),
folderId: attr('string'),
userId: attr('string'),
fullname: attr('string'),
permissions: belongsTo('space-permission')
});

View file

@ -1,13 +0,0 @@
import ApplicationSerializer from './application';
export default ApplicationSerializer.extend({
normalize(modelClass, resourceHash) {
return {
data: {
id: resourceHash.userId ? resourceHash.userId : 0,
type: modelClass.modelName,
attributes: resourceHash
}
};
}
});

View file

@ -6,37 +6,36 @@
</div>
<div class="input-control">
<div class="permissions-table">
{{#each permissions key="@index" as |permission|}}
{{#each permissions as |permission|}}
<div class="row">
<div class="permission-name-cell">{{permission.fullname}}</div>
<div class="permission-roles-cell">
<span class="role-category">Space:&nbsp;</span>
<input type="checkbox" id="space-role-view-{{permission.userId}}" checked={{permission.spaceView}} />
{{input type="checkbox" id=(concat 'space-role-view-' permission.userId) checked=permission.spaceView}}
<label for="space-role-view-{{permission.userId}}">view</label>&nbsp;&nbsp;
<input type="checkbox" id="space-role-manage-{{permission.userId}}" checked={{permission.spaceManage}} />
{{input type="checkbox" id=(concat 'space-role-manage-' permission.userId) checked=permission.spaceManage}}
<label for="space-role-manage-{{permission.userId}}">manage</label>&nbsp;&nbsp;
<input type="checkbox" id="space-role-owner-{{permission.userId}}" checked={{permission.spaceOwner}} />
{{input type="checkbox" id=(concat 'space-role-owner-' permission.userId) checked=permission.spaceOwner}}
<label for="space-role-owner-{{permission.userId}}">owner</label>&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;
<span class="role-category">Document:&nbsp;</span>
<input type="checkbox" id="doc-role-add-{{permission.userId}}" checked={{permission.documentAdd}} />
{{input type="checkbox" id=(concat 'doc-role-add-' permission.userId) checked=permission.documentAdd}}
<label for="doc-role-add-{{permission.userId}}">create</label>&nbsp;&nbsp;
<input type="checkbox" id="doc-role-edit-{{permission.userId}}" checked={{permission.documentEdit}} />
{{input type="checkbox" id=(concat 'doc-role-edit-' permission.userId) checked=permission.documentEdit}}
<label for="doc-role-edit-{{permission.userId}}">edit</label>&nbsp;&nbsp;
<input type="checkbox" id="doc-role-delete-{{permission.userId}}" checked={{permission.documentDelete}} />
{{input type="checkbox" id=(concat 'doc-role-delete-' permission.userId) checked=permission.documentDelete}}
<label for="doc-role-delete-{{permission.userId}}">delete</label>&nbsp;&nbsp;
<input type="checkbox" id="doc-role-move-{{permission.userId}}" checked={{permission.documentMove}} />
{{input type="checkbox" id=(concat 'doc-role-move-' permission.userId) checked=permission.documentMove}}
<label for="doc-role-move-{{permission.userId}}">move</label>&nbsp;&nbsp;
<input type="checkbox" id="doc-role-copy-{{permission.userId}}" checked={{permission.documentCopy}} />
{{input type="checkbox" id=(concat 'doc-role-copy-' permission.userId) checked=permission.documentCopy}}
<label for="doc-role-copy-{{permission.userId}}">copy</label>&nbsp;&nbsp;
<input type="checkbox" id="doc-role-template-{{permission.userId}}" checked={{permission.documentTemplate}} />
{{input type="checkbox" id=(concat 'doc-role-template-' permission.userId) checked=permission.documentTemplate}}
<label for="doc-role-template-{{permission.userId}}">templates</label>&nbsp;&nbsp;
</div>
</div>
{{/each}}
</div>
</div>
<div class="regular-button button-blue" {{action 'setPermissions'}}>GRANT</div>
</div>
</div>

View file

@ -1,19 +0,0 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import { Factory, faker } from 'ember-cli-mirage';
export default Factory.extend({
"folderId": faker.list.cycle("VzMuyEw_3WqiafcG", "VzMygEw_3WrtFzto"),
"userId": faker.list.cycle("VzMuyEw_3WqiafcE", "VzMuyEw_3WqiafcE"),
"canView": true,
"canEdit": true
});

View file

@ -71,39 +71,45 @@ func DecodeUserPermissions(perm []Permission) (r PermissionRecord) {
// for a given space, using flat permission summary record.
func EncodeUserPermissions(r PermissionRecord) (perm []Permission) {
if r.SpaceView {
perm = append(perm, encodeRecord(r, SpaceView))
perm = append(perm, EncodeRecord(r, SpaceView))
}
if r.SpaceManage {
perm = append(perm, encodeRecord(r, SpaceManage))
perm = append(perm, EncodeRecord(r, SpaceManage))
}
if r.SpaceOwner {
perm = append(perm, encodeRecord(r, SpaceOwner))
perm = append(perm, EncodeRecord(r, SpaceOwner))
}
if r.DocumentAdd {
perm = append(perm, encodeRecord(r, DocumentAdd))
perm = append(perm, EncodeRecord(r, DocumentAdd))
}
if r.DocumentEdit {
perm = append(perm, encodeRecord(r, DocumentEdit))
perm = append(perm, EncodeRecord(r, DocumentEdit))
}
if r.DocumentDelete {
perm = append(perm, encodeRecord(r, DocumentDelete))
perm = append(perm, EncodeRecord(r, DocumentDelete))
}
if r.DocumentMove {
perm = append(perm, encodeRecord(r, DocumentMove))
perm = append(perm, EncodeRecord(r, DocumentMove))
}
if r.DocumentCopy {
perm = append(perm, encodeRecord(r, DocumentCopy))
perm = append(perm, EncodeRecord(r, DocumentCopy))
}
if r.DocumentTemplate {
perm = append(perm, encodeRecord(r, DocumentTemplate))
perm = append(perm, EncodeRecord(r, DocumentTemplate))
}
return
}
// creates standard permission record representing user permissions for a space.
func encodeRecord(r PermissionRecord, a PermissionAction) (p Permission) {
// HasAnyPermission returns true if user has at least one permission.
func HasAnyPermission(p PermissionRecord) bool {
return p.SpaceView || p.SpaceManage || p.SpaceOwner || p.DocumentAdd || p.DocumentEdit ||
p.DocumentDelete || p.DocumentMove || p.DocumentCopy || p.DocumentTemplate
}
// EncodeRecord creates standard permission record representing user permissions for a space.
func EncodeRecord(r PermissionRecord, a PermissionAction) (p Permission) {
p = Permission{}
p.OrgID = r.OrgID
p.Who = "user"

View file

@ -104,10 +104,10 @@ type Viewer struct {
Email string `json:"email"`
}
// RolesModel details which users have what permissions on a given space.
type RolesModel struct {
// PermissionsModel details which users have what permissions on a given space.
type PermissionsModel struct {
Message string
Permissions []Permission
Permissions []PermissionRecord
}
// AcceptShareModel is used to setup a user who has accepted a shared space.