1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-08-04 21:15:24 +02:00

space categorty management

This commit is contained in:
Harvey Kandola 2017-09-19 17:58:33 +01:00
parent a86d52388e
commit 4874d23f15
19 changed files with 915 additions and 40 deletions

285
domain/category/endpoint.go Normal file
View file

@ -0,0 +1,285 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
// Package category handles API calls and persistence for categories.
// Categories sub-divide spaces.
package category
import (
"database/sql"
"encoding/json"
"io/ioutil"
"net/http"
"github.com/documize/community/core/env"
"github.com/documize/community/core/request"
"github.com/documize/community/core/response"
"github.com/documize/community/core/uniqueid"
"github.com/documize/community/domain"
"github.com/documize/community/domain/permission"
"github.com/documize/community/model/audit"
"github.com/documize/community/model/category"
pm "github.com/documize/community/model/permission"
)
// Handler contains the runtime information such as logging and database.
type Handler struct {
Runtime *env.Runtime
Store *domain.Store
}
// Add saves space category.
func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
method := "category.add"
ctx := domain.GetRequestContext(r)
if !ctx.Authenticated {
response.WriteForbiddenError(w)
return
}
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
if err != nil {
response.WriteBadRequestError(w, method, "body")
h.Runtime.Log.Error(method, err)
return
}
var cat category.Category
err = json.Unmarshal(body, &cat)
if err != nil {
response.WriteBadRequestError(w, method, "category")
h.Runtime.Log.Error(method, err)
return
}
cat.RefID = uniqueid.Generate()
cat.OrgID = ctx.OrgID
ctx.Transaction, err = h.Runtime.Db.Beginx()
if err != nil {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
err = h.Store.Category.Add(ctx, cat)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
h.Store.Audit.Record(ctx, audit.EventTypeCategoryAdd)
ctx.Transaction.Commit()
cat, err = h.Store.Category.Get(ctx, cat.RefID)
if err != nil {
response.WriteServerError(w, method, err)
return
}
response.WriteJSON(w, cat)
}
// Get returns categories visible to user within a space.
func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
method := "category.get"
ctx := domain.GetRequestContext(r)
spaceID := request.Param(r, "spaceID")
if len(spaceID) == 0 {
response.WriteMissingDataError(w, method, "spaceID")
return
}
ok := permission.HasPermission(ctx, *h.Store, spaceID,
pm.SpaceManage, pm.SpaceOwner, pm.SpaceView)
if !ok {
response.WriteForbiddenError(w)
return
}
cat, err := h.Store.Category.GetBySpace(ctx, spaceID)
if err != nil && err != sql.ErrNoRows {
response.WriteServerError(w, method, err)
return
}
if len(cat) == 0 {
cat = []category.Category{}
}
response.WriteJSON(w, cat)
}
// GetAll returns categories within a space, disregarding permissions.
// Used in admin screens, lists, functions.
func (h *Handler) GetAll(w http.ResponseWriter, r *http.Request) {
method := "category.getAll"
ctx := domain.GetRequestContext(r)
spaceID := request.Param(r, "spaceID")
if len(spaceID) == 0 {
response.WriteMissingDataError(w, method, "spaceID")
return
}
cat, err := h.Store.Category.GetAllBySpace(ctx, spaceID)
if err != nil && err != sql.ErrNoRows {
response.WriteServerError(w, method, err)
return
}
if len(cat) == 0 {
cat = []category.Category{}
}
response.WriteJSON(w, cat)
}
// Update saves existing space category.
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
method := "category.update"
ctx := domain.GetRequestContext(r)
categoryID := request.Param(r, "categoryID")
if len(categoryID) == 0 {
response.WriteMissingDataError(w, method, "categoryID")
return
}
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
if err != nil {
response.WriteBadRequestError(w, method, "body")
h.Runtime.Log.Error(method, err)
return
}
var cat category.Category
err = json.Unmarshal(body, &cat)
if err != nil {
response.WriteBadRequestError(w, method, "category")
h.Runtime.Log.Error(method, err)
return
}
cat.OrgID = ctx.OrgID
cat.RefID = categoryID
ok := permission.HasPermission(ctx, *h.Store, cat.LabelID, pm.SpaceManage, pm.SpaceOwner)
if !ok || !ctx.Authenticated {
response.WriteForbiddenError(w)
return
}
ctx.Transaction, err = h.Runtime.Db.Beginx()
if err != nil {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
err = h.Store.Category.Update(ctx, cat)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
h.Store.Audit.Record(ctx, audit.EventTypeCategoryUpdate)
ctx.Transaction.Commit()
cat, err = h.Store.Category.Get(ctx, cat.RefID)
if err != nil {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
response.WriteJSON(w, cat)
}
// Delete removes category and associated member records.
func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
method := "category.delete"
ctx := domain.GetRequestContext(r)
catID := request.Param(r, "categoryID")
if len(catID) == 0 {
response.WriteMissingDataError(w, method, "categoryID")
return
}
cat, err := h.Store.Category.Get(ctx, catID)
if err != nil {
response.WriteServerError(w, method, err)
return
}
ok := permission.HasPermission(ctx, *h.Store, cat.LabelID, pm.SpaceManage, pm.SpaceOwner)
if !ok || !ctx.Authenticated {
response.WriteForbiddenError(w)
return
}
ctx.Transaction, err = h.Runtime.Db.Beginx()
if err != nil {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
// remove category members
_, err = h.Store.Category.RemoveCategoryMembership(ctx, cat.RefID)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
// remove category permissions
_, err = h.Store.Permission.DeleteCategoryPermissions(ctx, cat.RefID)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
// remove category
_, err = h.Store.Category.Delete(ctx, cat.RefID)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
h.Store.Audit.Record(ctx, audit.EventTypeCategoryDelete)
ctx.Transaction.Commit()
response.WriteEmpty(w)
}
/*
6. add category view permission !!!
7. link/unlink document to category
8. filter space documents by category -- URL param? nested route?
*/

View file

@ -0,0 +1,201 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
// Package mysql handles data persistence for both category definition
// and and document/category association.
package mysql
import (
"database/sql"
"fmt"
"time"
"github.com/documize/community/core/env"
"github.com/documize/community/core/streamutil"
"github.com/documize/community/domain"
"github.com/documize/community/domain/store/mysql"
"github.com/documize/community/model/category"
"github.com/pkg/errors"
)
// Scope provides data access to MySQL.
type Scope struct {
Runtime *env.Runtime
}
// Add inserts the given record into the category table.
func (s Scope) Add(ctx domain.RequestContext, c category.Category) (err error) {
c.Created = time.Now().UTC()
c.Revised = time.Now().UTC()
stmt, err := ctx.Transaction.Preparex("INSERT INTO category (refid, orgid, labelid, category, created, revised) VALUES (?, ?, ?, ?, ?, ?)")
defer streamutil.Close(stmt)
if err != nil {
err = errors.Wrap(err, "unable to prepare insert category")
return
}
_, err = stmt.Exec(c.RefID, c.OrgID, c.LabelID, c.Category, c.Created, c.Revised)
if err != nil {
err = errors.Wrap(err, "unable to execute insert category")
return
}
return
}
// GetBySpace returns space categories for a user.
// Context is used to for user ID.
func (s Scope) GetBySpace(ctx domain.RequestContext, spaceID string) (c []category.Category, err error) {
err = s.Runtime.Db.Select(&c, `
SELECT id, refid, orgid, labelid, category, created, revised FROM category
WHERE orgid=? AND labelid=?
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='category' AND refid IN (
SELECT refid from permission WHERE orgid=? AND who='user' AND whoid=? AND location='category' 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='category'
AND p.action='view' AND r.userid=?
))
ORDER BY category`, ctx.OrgID, spaceID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
if err == sql.ErrNoRows {
err = nil
}
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("unable to execute select categories for space %s", spaceID))
return
}
return
}
// GetAllBySpace returns all space categories.
func (s Scope) GetAllBySpace(ctx domain.RequestContext, spaceID string) (c []category.Category, err error) {
err = s.Runtime.Db.Select(&c, `
SELECT id, refid, orgid, labelid, category, created, revised FROM category
WHERE orgid=? AND labelid=?
AND labelid 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 category`, ctx.OrgID, spaceID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
if err == sql.ErrNoRows {
err = nil
}
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("unable to execute select all categories for space %s", spaceID))
return
}
return
}
// Update saves category name change.
func (s Scope) Update(ctx domain.RequestContext, c category.Category) (err error) {
c.Revised = time.Now().UTC()
stmt, err := ctx.Transaction.PrepareNamed("UPDATE category SET category=:category, revised=:revised WHERE orgid=:orgid AND refid=:refid")
defer streamutil.Close(stmt)
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("unable to prepare update for category %s", c.RefID))
return
}
_, err = stmt.Exec(&c)
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("unable to execute update for category %s", c.RefID))
return
}
return
}
// Get returns specified category
func (s Scope) Get(ctx domain.RequestContext, id string) (c category.Category, err error) {
stmt, err := s.Runtime.Db.Preparex("SELECT id, refid, orgid, labelid, category, created, revised FROM category WHERE orgid=? AND refid=?")
defer streamutil.Close(stmt)
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("unable to prepare select for category %s", id))
return
}
err = stmt.Get(&c, ctx.OrgID, id)
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("unable to get category %s", id))
return
}
return
}
// Delete removes category from the store.
func (s Scope) Delete(ctx domain.RequestContext, id string) (rows int64, err error) {
b := mysql.BaseQuery{}
return b.DeleteConstrained(ctx.Transaction, "category", ctx.OrgID, id)
}
// AssociateDocument inserts category membership record into the category member table.
func (s Scope) AssociateDocument(ctx domain.RequestContext, m category.Member) (err error) {
m.Created = time.Now().UTC()
m.Revised = time.Now().UTC()
stmt, err := ctx.Transaction.Preparex("INSERT INTO categorymember (refid, orgid, categoryid, labelid, documentid, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?)")
defer streamutil.Close(stmt)
if err != nil {
err = errors.Wrap(err, "unable to prepare insert categorymember")
return
}
_, err = stmt.Exec(m.RefID, m.OrgID, m.CategoryID, m.LabelID, m.DocumentID, m.Created, m.Revised)
if err != nil {
err = errors.Wrap(err, "unable to execute insert categorymember")
return
}
return
}
// DisassociateDocument removes document associatation from category.
func (s Scope) DisassociateDocument(ctx domain.RequestContext, categoryID, documentID string) (rows int64, err error) {
b := mysql.BaseQuery{}
sql := fmt.Sprintf("DELETE FROM categorymember WHERE orgid='%s' AND categoryid='%s' AND documentid='%s'",
ctx.OrgID, categoryID, documentID)
return b.DeleteWhere(ctx.Transaction, sql)
}
// RemoveCategoryMembership removes all category associations from the store.
func (s Scope) RemoveCategoryMembership(ctx domain.RequestContext, categoryID string) (rows int64, err error) {
b := mysql.BaseQuery{}
sql := fmt.Sprintf("DELETE FROM categorymember WHERE orgid='%s' AND categoryid='%s'",
ctx.OrgID, categoryID)
return b.DeleteWhere(ctx.Transaction, sql)
}
// DeleteBySpace removes all category and category associations for given space.
func (s Scope) DeleteBySpace(ctx domain.RequestContext, spaceID string) (rows int64, err error) {
b := mysql.BaseQuery{}
s1 := fmt.Sprintf("DELETE FROM categorymember WHERE orgid='%s' AND labelid='%s'", ctx.OrgID, spaceID)
b.DeleteWhere(ctx.Transaction, s1)
s2 := fmt.Sprintf("DELETE FROM category WHERE orgid='%s' AND labelid='%s'", ctx.OrgID, spaceID)
return b.DeleteWhere(ctx.Transaction, s2)
}

View file

@ -134,3 +134,24 @@ func (s Scope) DeleteUserPermissions(ctx domain.RequestContext, userID string) (
return b.DeleteWhere(ctx.Transaction, sql)
}
// DeleteCategoryPermissions removes records from permissions table for given category ID.
func (s Scope) DeleteCategoryPermissions(ctx domain.RequestContext, categoryID string) (rows int64, err error) {
b := mysql.BaseQuery{}
sql := fmt.Sprintf("DELETE FROM permission WHERE orgid='%s' AND location='category' AND refid='%s'", ctx.OrgID, categoryID)
return b.DeleteWhere(ctx.Transaction, sql)
}
// DeleteSpaceCategoryPermissions removes all category permission for for given space.
func (s Scope) DeleteSpaceCategoryPermissions(ctx domain.RequestContext, spaceID string) (rows int64, err error) {
b := mysql.BaseQuery{}
sql := fmt.Sprintf(`
DELETE FROM permission WHERE orgid='%s' AND location='category'
AND refid IN (SELECT refid FROM category WHERE orgid='%s' AND labelid='%s')`,
ctx.OrgID, ctx.OrgID, spaceID)
return b.DeleteWhere(ctx.Transaction, sql)
}

View file

@ -30,7 +30,7 @@ func CanViewSpaceDocument(ctx domain.RequestContext, s domain.Store, labelID str
for _, role := range roles {
if role.RefID == labelID && role.Location == "space" && role.Scope == "object" &&
pm.HasPermission(role.Action, pm.SpaceView, pm.SpaceManage, pm.SpaceOwner) {
pm.ContainsPermission(role.Action, pm.SpaceView, pm.SpaceManage, pm.SpaceOwner) {
return true
}
}
@ -58,7 +58,7 @@ func CanViewDocument(ctx domain.RequestContext, s domain.Store, documentID strin
for _, role := range roles {
if role.RefID == document.LabelID && role.Location == "space" && role.Scope == "object" &&
pm.HasPermission(role.Action, pm.SpaceView, pm.SpaceManage, pm.SpaceOwner) {
pm.ContainsPermission(role.Action, pm.SpaceView, pm.SpaceManage, pm.SpaceOwner) {
return true
}
}
@ -136,7 +136,7 @@ func CanUploadDocument(ctx domain.RequestContext, s domain.Store, spaceID string
for _, role := range roles {
if role.RefID == spaceID && role.Location == "space" && role.Scope == "object" &&
pm.HasPermission(role.Action, pm.DocumentAdd) {
pm.ContainsPermission(role.Action, pm.DocumentAdd) {
return true
}
}
@ -156,7 +156,7 @@ func CanViewSpace(ctx domain.RequestContext, s domain.Store, spaceID string) boo
for _, role := range roles {
if role.RefID == spaceID && role.Location == "space" && role.Scope == "object" &&
pm.HasPermission(role.Action, pm.SpaceView, pm.SpaceManage, pm.SpaceOwner) {
pm.ContainsPermission(role.Action, pm.SpaceView, pm.SpaceManage, pm.SpaceOwner) {
return true
}
}
@ -164,18 +164,9 @@ func CanViewSpace(ctx domain.RequestContext, s domain.Store, spaceID string) boo
return false
}
// HasDocumentAction returns if user can perform specified action.
func HasDocumentAction(ctx domain.RequestContext, s domain.Store, documentID string, a pm.Action) bool {
document, err := s.Document.Get(ctx, documentID)
if err == sql.ErrNoRows {
err = nil
}
if err != nil {
return false
}
roles, err := s.Permission.GetUserSpacePermissions(ctx, document.LabelID)
// HasPermission returns if user can perform specified actions.
func HasPermission(ctx domain.RequestContext, s domain.Store, spaceID string, actions ...pm.Action) bool {
roles, err := s.Permission.GetUserSpacePermissions(ctx, spaceID)
if err == sql.ErrNoRows {
err = nil
@ -185,8 +176,12 @@ func HasDocumentAction(ctx domain.RequestContext, s domain.Store, documentID str
}
for _, role := range roles {
if role.RefID == document.LabelID && role.Location == "space" && role.Scope == "object" && role.Action == a {
return true
if role.RefID == spaceID && role.Location == "space" && role.Scope == "object" {
for _, a := range actions {
if role.Action == a {
return true
}
}
}
}

View file

@ -48,7 +48,7 @@ type Handler struct {
// Add creates a new space.
func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
method := "space.Add"
method := "space.add"
ctx := domain.GetRequestContext(r)
if !h.Runtime.Product.License.IsValid() {
@ -276,7 +276,7 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
// Get returns the requested space.
func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
method := "Get"
method := "space.get"
ctx := domain.GetRequestContext(r)
id := request.Param(r, "spaceID")
@ -302,7 +302,7 @@ func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
// GetAll returns spaces the user can see.
func (h *Handler) GetAll(w http.ResponseWriter, r *http.Request) {
method := "GetAll"
method := "space.getAll"
ctx := domain.GetRequestContext(r)
sp, err := h.Store.Space.GetAll(ctx)
@ -322,7 +322,7 @@ func (h *Handler) GetAll(w http.ResponseWriter, r *http.Request) {
// GetSpaceViewers returns the users that can see the shared spaces.
func (h *Handler) GetSpaceViewers(w http.ResponseWriter, r *http.Request) {
method := "space.Viewers"
method := "space.viewers"
ctx := domain.GetRequestContext(r)
v, err := h.Store.Space.Viewers(ctx)
@ -341,7 +341,7 @@ func (h *Handler) GetSpaceViewers(w http.ResponseWriter, r *http.Request) {
// Update processes request to save space object to the database
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
method := "space.Update"
method := "space.update"
ctx := domain.GetRequestContext(r)
if !ctx.Editor {
@ -403,7 +403,7 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
// Remove moves documents to another space before deleting it
func (h *Handler) Remove(w http.ResponseWriter, r *http.Request) {
method := "space.Remove"
method := "space.remove"
ctx := domain.GetRequestContext(r)
if !h.Runtime.Product.License.IsValid() {
@ -477,7 +477,7 @@ func (h *Handler) Remove(w http.ResponseWriter, r *http.Request) {
// Delete removes space.
func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
method := "space.Delete"
method := "space.delete"
ctx := domain.GetRequestContext(r)
if !h.Runtime.Product.License.IsValid() {
@ -512,7 +512,7 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
return
}
_, err = h.Store.Space.Delete(ctx, id)
_, err = h.Store.Permission.DeleteSpacePermissions(ctx, id)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
@ -520,7 +520,8 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
return
}
_, err = h.Store.Permission.DeleteSpacePermissions(ctx, id)
// remove category permissions
_, err = h.Store.Permission.DeleteSpaceCategoryPermissions(ctx, id)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
@ -536,6 +537,23 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
return
}
// remove category and members for space
_, err = h.Store.Category.DeleteBySpace(ctx, id)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
_, err = h.Store.Space.Delete(ctx, id)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
h.Store.Audit.Record(ctx, audit.EventTypeSpaceDelete)
ctx.Transaction.Commit()

View file

@ -18,6 +18,7 @@ import (
"github.com/documize/community/model/attachment"
"github.com/documize/community/model/audit"
"github.com/documize/community/model/block"
"github.com/documize/community/model/category"
"github.com/documize/community/model/doc"
"github.com/documize/community/model/link"
"github.com/documize/community/model/org"
@ -36,6 +37,7 @@ type Store struct {
Attachment AttachmentStorer
Audit AuditStorer
Block BlockStorer
Category CategoryStorer
Document DocumentStorer
Link LinkStorer
Organization OrganizationStorer
@ -59,6 +61,20 @@ type SpaceStorer interface {
Delete(ctx RequestContext, id string) (rows int64, err error)
}
// CategoryStorer defines required methods for category and category membership management
type CategoryStorer interface {
Add(ctx RequestContext, c category.Category) (err error)
Update(ctx RequestContext, c category.Category) (err error)
Get(ctx RequestContext, id string) (c category.Category, err error)
GetBySpace(ctx RequestContext, spaceID string) (c []category.Category, err error)
GetAllBySpace(ctx RequestContext, spaceID string) (c []category.Category, err error)
Delete(ctx RequestContext, id string) (rows int64, err error)
AssociateDocument(ctx RequestContext, m category.Member) (err error)
DisassociateDocument(ctx RequestContext, categoryID, documentID string) (rows int64, err error)
RemoveCategoryMembership(ctx RequestContext, categoryID string) (rows int64, err error)
DeleteBySpace(ctx RequestContext, spaceID string) (rows int64, err error)
}
// PermissionStorer defines required methods for space/document permission management
type PermissionStorer interface {
AddPermission(ctx RequestContext, r permission.Permission) (err error)
@ -68,6 +84,8 @@ type PermissionStorer interface {
DeleteSpacePermissions(ctx RequestContext, spaceID string) (rows int64, err error)
DeleteUserSpacePermissions(ctx RequestContext, spaceID, userID string) (rows int64, err error)
DeleteUserPermissions(ctx RequestContext, userID string) (rows int64, err error)
DeleteCategoryPermissions(ctx RequestContext, categoryID string) (rows int64, err error)
DeleteSpaceCategoryPermissions(ctx RequestContext, spaceID string) (rows int64, err error)
}
// UserStorer defines required methods for user management

View file

@ -113,21 +113,21 @@ func (h *Handler) SaveAs(w http.ResponseWriter, r *http.Request) {
return
}
if !permission.HasDocumentAction(ctx, *h.Store, model.DocumentID, pm.DocumentTemplate) {
response.WriteForbiddenError(w)
return
}
// DB transaction
ctx.Transaction, err = h.Runtime.Db.Beginx()
// Duplicate document
doc, err := h.Store.Document.Get(ctx, model.DocumentID)
if err != nil {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
// Duplicate document
doc, err := h.Store.Document.Get(ctx, model.DocumentID)
if !permission.HasPermission(ctx, *h.Store, doc.LabelID, pm.DocumentTemplate) {
response.WriteForbiddenError(w)
return
}
// DB transaction
ctx.Transaction, err = h.Runtime.Db.Beginx()
if err != nil {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)