mirror of
https://github.com/documize/community.git
synced 2025-08-04 21:15:24 +02:00
document level permissions
This commit is contained in:
parent
f4f32bcfcb
commit
b9394a4967
28 changed files with 983 additions and 355 deletions
|
@ -69,7 +69,7 @@ func (h *Handler) SetSpacePermissions(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
var model = permission.PermissionsModel{}
|
||||
var model = permission.SpaceRequestModel{}
|
||||
err = json.Unmarshal(body, &model)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
|
@ -398,3 +398,192 @@ func (h *Handler) SetCategoryPermissions(w http.ResponseWriter, r *http.Request)
|
|||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
||||
// GetDocumentPermissions returns permissions for all users for given document.
|
||||
func (h *Handler) GetDocumentPermissions(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.GetDocumentPermissions"
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
documentID := request.Param(r, "documentID")
|
||||
if len(documentID) == 0 {
|
||||
response.WriteMissingDataError(w, method, "documentID")
|
||||
return
|
||||
}
|
||||
|
||||
perms, err := h.Store.Permission.GetDocumentPermissions(ctx, documentID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
if len(perms) == 0 {
|
||||
perms = []permission.Permission{}
|
||||
}
|
||||
|
||||
userPerms := make(map[string][]permission.Permission)
|
||||
for _, p := range perms {
|
||||
userPerms[p.WhoID] = append(userPerms[p.WhoID], p)
|
||||
}
|
||||
|
||||
records := []permission.DocumentRecord{}
|
||||
for _, up := range userPerms {
|
||||
records = append(records, permission.DecodeUserDocumentPermissions(up))
|
||||
}
|
||||
|
||||
response.WriteJSON(w, records)
|
||||
}
|
||||
|
||||
// GetUserDocumentPermissions returns permissions for the requested space, for current user.
|
||||
func (h *Handler) GetUserDocumentPermissions(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.GetUserDocumentPermissions"
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
documentID := request.Param(r, "documentID")
|
||||
if len(documentID) == 0 {
|
||||
response.WriteMissingDataError(w, method, "documentID")
|
||||
return
|
||||
}
|
||||
|
||||
perms, err := h.Store.Permission.GetUserDocumentPermissions(ctx, documentID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
if len(perms) == 0 {
|
||||
perms = []permission.Permission{}
|
||||
}
|
||||
|
||||
record := permission.DecodeUserDocumentPermissions(perms)
|
||||
response.WriteJSON(w, record)
|
||||
}
|
||||
|
||||
// SetDocumentPermissions persists specified document permissions
|
||||
// These permissions override document permissions
|
||||
func (h *Handler) SetDocumentPermissions(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.SetDocumentPermissions"
|
||||
ctx := domain.GetRequestContext(r)
|
||||
|
||||
id := request.Param(r, "documentID")
|
||||
if len(id) == 0 {
|
||||
response.WriteMissingDataError(w, method, "documentID")
|
||||
return
|
||||
}
|
||||
|
||||
doc, err := h.Store.Document.Get(ctx, id)
|
||||
if err != nil {
|
||||
response.WriteNotFoundError(w, method, "document not found")
|
||||
return
|
||||
}
|
||||
|
||||
sp, err := h.Store.Space.Get(ctx, doc.LabelID)
|
||||
if err != nil {
|
||||
response.WriteNotFoundError(w, method, "space not found")
|
||||
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 {
|
||||
response.WriteBadRequestError(w, method, err.Error())
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
var model = []permission.DocumentRecord{}
|
||||
err = json.Unmarshal(body, &model)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// We compare new permisions to what we had before.
|
||||
// Why? So we can send out space invitation emails.
|
||||
previousRoles, err := h.Store.Permission.GetDocumentPermissions(ctx, id)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Store all previous approval roles as map for easy querying
|
||||
previousRoleUsers := make(map[string]bool)
|
||||
for _, v := range previousRoles {
|
||||
if v.Action == permission.DocumentApprove {
|
||||
previousRoleUsers[v.WhoID] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Get user who is setting document permissions so we can send out emails with context
|
||||
inviter, err := h.Store.User.Get(ctx, ctx.UserID)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Nuke all previous permissions for this document
|
||||
_, err = h.Store.Permission.DeleteDocumentPermissions(ctx, id)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
||||
url := ctx.GetAppURL(fmt.Sprintf("s/%s/%s/d/%s/%s",
|
||||
sp.RefID, stringutil.MakeSlug(sp.Name), doc.RefID, stringutil.MakeSlug(doc.Title)))
|
||||
|
||||
for _, perm := range model {
|
||||
perm.OrgID = ctx.OrgID
|
||||
perm.DocumentID = id
|
||||
|
||||
// Only persist if there is a role!
|
||||
if permission.HasAnyDocumentPermission(perm) {
|
||||
r := permission.EncodeUserDocumentPermissions(perm)
|
||||
|
||||
for _, p := range r {
|
||||
err = h.Store.Permission.AddPermission(ctx, p)
|
||||
if err != nil {
|
||||
h.Runtime.Log.Error("set document permission", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Send email notification to users who have been given document approver role
|
||||
if _, isExisting := previousRoleUsers[perm.UserID]; !isExisting {
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h.Store.Audit.Record(ctx, audit.EventTypeDocumentPermission)
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
|
|
@ -212,3 +212,55 @@ func (s Scope) GetUserCategoryPermissions(ctx domain.RequestContext, userID stri
|
|||
|
||||
return
|
||||
}
|
||||
|
||||
// GetUserDocumentPermissions returns document permissions for user.
|
||||
// Context is used to for user ID.
|
||||
func (s Scope) GetUserDocumentPermissions(ctx domain.RequestContext, documentID 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='document' 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 LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.location='document' AND refid=?
|
||||
AND p.who='role' AND (r.userid=? OR r.userid='0')`,
|
||||
ctx.OrgID, documentID, ctx.UserID, ctx.OrgID, documentID, ctx.OrgID)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute select user document permissions %s", ctx.UserID))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GetDocumentPermissions returns documents permissions for all users.
|
||||
func (s Scope) GetDocumentPermissions(ctx domain.RequestContext, documentID 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='document' AND refid=? AND who='user'
|
||||
UNION ALL
|
||||
SELECT p.id, p.orgid, p.who, p.whoid, p.action, p.scope, p.location, p.refid
|
||||
FROM permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.location='document' AND p.refid=?
|
||||
AND p.who='role'`,
|
||||
ctx.OrgID, documentID, ctx.OrgID, documentID)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute select document permissions %s", ctx.UserID))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteDocumentPermissions removes records from permissions table for given document.
|
||||
func (s Scope) DeleteDocumentPermissions(ctx domain.RequestContext, documentID string) (rows int64, err error) {
|
||||
b := mysql.BaseQuery{}
|
||||
|
||||
sql := fmt.Sprintf("DELETE FROM permission WHERE orgid='%s' AND location='document' AND refid='%s'", ctx.OrgID, documentID)
|
||||
|
||||
return b.DeleteWhere(ctx.Transaction, sql)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue