mirror of
https://github.com/documize/community.git
synced 2025-07-20 13:49:42 +02:00
re-working space permissions -- WIP
This commit is contained in:
parent
c51ba65b1d
commit
ae05cacf3f
37 changed files with 735 additions and 601 deletions
|
@ -34,7 +34,7 @@ func (s Scope) Add(ctx domain.RequestContext, account account.Account) (err erro
|
||||||
account.Created = time.Now().UTC()
|
account.Created = time.Now().UTC()
|
||||||
account.Revised = time.Now().UTC()
|
account.Revised = time.Now().UTC()
|
||||||
|
|
||||||
stmt, err := ctx.Transaction.Preparex("INSERT INTO account (refid, orgid, userid, admin, editor, users, active, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
|
stmt, err := ctx.Transaction.Preparex("INSERT INTO account (refid, orgid, userid, admin, editor, users, active, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
||||||
defer streamutil.Close(stmt)
|
defer streamutil.Close(stmt)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -15,12 +15,12 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
"github.com/documize/community/domain"
|
"github.com/documize/community/domain"
|
||||||
|
sp "github.com/documize/community/model/space"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CanViewDocumentInFolder returns if the user has permission to view a document within the specified folder.
|
// CanViewDocumentInFolder returns if the user has permission to view a document within the specified folder.
|
||||||
func CanViewDocumentInFolder(ctx domain.RequestContext, s domain.Store, labelID string) (hasPermission bool) {
|
func CanViewDocumentInFolder(ctx domain.RequestContext, s domain.Store, labelID string) bool {
|
||||||
roles, err := s.Space.GetUserRoles(ctx)
|
roles, err := s.Space.GetUserPermissions(ctx, labelID)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,8 @@ func CanViewDocumentInFolder(ctx domain.RequestContext, s domain.Store, labelID
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
if role.LabelID == labelID && (role.CanView || role.CanEdit) {
|
if role.RefID == labelID && role.Location == "space" && role.Scope == "object" &&
|
||||||
|
sp.HasPermission(role.Action, sp.SpaceView, sp.SpaceManage, sp.SpaceOwner) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,10 +38,9 @@ func CanViewDocumentInFolder(ctx domain.RequestContext, s domain.Store, labelID
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanViewDocument returns if the clinet has permission to view a given document.
|
// CanViewDocument returns if the client has permission to view a given document.
|
||||||
func CanViewDocument(ctx domain.RequestContext, s domain.Store, documentID string) (hasPermission bool) {
|
func CanViewDocument(ctx domain.RequestContext, s domain.Store, documentID string) bool {
|
||||||
document, err := s.Document.Get(ctx, documentID)
|
document, err := s.Document.Get(ctx, documentID)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
|
@ -48,8 +48,7 @@ func CanViewDocument(ctx domain.RequestContext, s domain.Store, documentID strin
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
roles, err := s.Space.GetUserRoles(ctx)
|
roles, err := s.Space.GetUserPermissions(ctx, document.LabelID)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
|
@ -58,7 +57,8 @@ func CanViewDocument(ctx domain.RequestContext, s domain.Store, documentID strin
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
if role.LabelID == document.LabelID && (role.CanView || role.CanEdit) {
|
if role.RefID == document.LabelID && role.Location == "space" && role.Scope == "object" &&
|
||||||
|
sp.HasPermission(role.Action, sp.SpaceView, sp.SpaceManage, sp.SpaceOwner) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ func CanViewDocument(ctx domain.RequestContext, s domain.Store, documentID strin
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanChangeDocument returns if the clinet has permission to change a given document.
|
// CanChangeDocument returns if the clinet has permission to change a given document.
|
||||||
func CanChangeDocument(ctx domain.RequestContext, s domain.Store, documentID string) (hasPermission bool) {
|
func CanChangeDocument(ctx domain.RequestContext, s domain.Store, documentID string) bool {
|
||||||
document, err := s.Document.Get(ctx, documentID)
|
document, err := s.Document.Get(ctx, documentID)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
|
@ -77,7 +77,7 @@ func CanChangeDocument(ctx domain.RequestContext, s domain.Store, documentID str
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
roles, err := s.Space.GetUserRoles(ctx)
|
roles, err := s.Space.GetUserPermissions(ctx, document.LabelID)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
|
@ -87,7 +87,8 @@ func CanChangeDocument(ctx domain.RequestContext, s domain.Store, documentID str
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
if role.LabelID == document.LabelID && role.CanEdit {
|
if role.RefID == document.LabelID && role.Location == "space" && role.Scope == "object" &&
|
||||||
|
sp.HasPermission(role.Action, sp.DocumentEdit) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,10 +96,9 @@ func CanChangeDocument(ctx domain.RequestContext, s domain.Store, documentID str
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanUploadDocument returns if the client has permission to upload documents to the given folderID.
|
// CanUploadDocument returns if the client has permission to upload documents to the given space.
|
||||||
func CanUploadDocument(ctx domain.RequestContext, s domain.Store, folderID string) (hasPermission bool) {
|
func CanUploadDocument(ctx domain.RequestContext, s domain.Store, spaceID string) bool {
|
||||||
roles, err := s.Space.GetUserRoles(ctx)
|
roles, err := s.Space.GetUserPermissions(ctx, spaceID)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,8 @@ func CanUploadDocument(ctx domain.RequestContext, s domain.Store, folderID strin
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
if role.LabelID == folderID && role.CanEdit {
|
if role.RefID == spaceID && role.Location == "space" && role.Scope == "object" &&
|
||||||
|
sp.HasPermission(role.Action, sp.DocumentAdd) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,12 +168,12 @@ func (m *Mailer) PasswordReset(recipient, url string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShareFolderExistingUser provides an existing user with a link to a newly shared folder.
|
// ShareSpaceExistingUser provides an existing user with a link to a newly shared space.
|
||||||
func (m *Mailer) ShareFolderExistingUser(recipient, inviter, url, folder, intro string) {
|
func (m *Mailer) ShareSpaceExistingUser(recipient, inviter, url, folder, intro string) {
|
||||||
method := "ShareFolderExistingUser"
|
method := "ShareSpaceExistingUser"
|
||||||
m.LoadCredentials()
|
m.LoadCredentials()
|
||||||
|
|
||||||
file, err := web.ReadFile("mail/share-folder-existing-user.html")
|
file, err := web.ReadFile("mail/share-space-existing-user.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.Runtime.Log.Error(fmt.Sprintf("%s - unable to load email template", method), err)
|
m.Runtime.Log.Error(fmt.Sprintf("%s - unable to load email template", method), err)
|
||||||
return
|
return
|
||||||
|
@ -218,12 +218,12 @@ func (m *Mailer) ShareFolderExistingUser(recipient, inviter, url, folder, intro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShareFolderNewUser invites new user providing Credentials, explaining the product and stating who is inviting them.
|
// ShareSpaceNewUser invites new user providing Credentials, explaining the product and stating who is inviting them.
|
||||||
func (m *Mailer) ShareFolderNewUser(recipient, inviter, url, folder, invitationMessage string) {
|
func (m *Mailer) ShareSpaceNewUser(recipient, inviter, url, space, invitationMessage string) {
|
||||||
method := "ShareFolderNewUser"
|
method := "ShareSpaceNewUser"
|
||||||
m.LoadCredentials()
|
m.LoadCredentials()
|
||||||
|
|
||||||
file, err := web.ReadFile("mail/share-folder-new-user.html")
|
file, err := web.ReadFile("mail/share-space-new-user.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.Runtime.Log.Error(fmt.Sprintf("%s - unable to load email template", method), err)
|
m.Runtime.Log.Error(fmt.Sprintf("%s - unable to load email template", method), err)
|
||||||
return
|
return
|
||||||
|
@ -236,7 +236,7 @@ func (m *Mailer) ShareFolderNewUser(recipient, inviter, url, folder, invitationM
|
||||||
inviter = "Your colleague"
|
inviter = "Your colleague"
|
||||||
}
|
}
|
||||||
|
|
||||||
subject := fmt.Sprintf("%s has shared %s with you on Documize", inviter, folder)
|
subject := fmt.Sprintf("%s has shared %s with you on Documize", inviter, space)
|
||||||
|
|
||||||
e := NewEmail()
|
e := NewEmail()
|
||||||
e.From = m.Credentials.SMTPsender
|
e.From = m.Credentials.SMTPsender
|
||||||
|
@ -254,7 +254,7 @@ func (m *Mailer) ShareFolderNewUser(recipient, inviter, url, folder, invitationM
|
||||||
inviter,
|
inviter,
|
||||||
url,
|
url,
|
||||||
invitationMessage,
|
invitationMessage,
|
||||||
folder,
|
space,
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer := new(bytes.Buffer)
|
buffer := new(bytes.Buffer)
|
||||||
|
|
|
@ -106,15 +106,16 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
role := space.Role{}
|
perm := space.Permission{}
|
||||||
role.LabelID = sp.RefID
|
perm.OrgID = sp.OrgID
|
||||||
role.OrgID = sp.OrgID
|
perm.Who = "user"
|
||||||
role.UserID = ctx.UserID
|
perm.WhoID = ctx.UserID
|
||||||
role.CanEdit = true
|
perm.Scope = "object"
|
||||||
role.CanView = true
|
perm.Location = "space"
|
||||||
role.RefID = uniqueid.Generate()
|
perm.RefID = sp.RefID
|
||||||
|
perm.Action = "" // we send array for actions below
|
||||||
|
|
||||||
err = h.Store.Space.AddRole(ctx, role)
|
err = h.Store.Space.AddPermissions(ctx, perm, space.SpaceOwner, space.SpaceManage, space.SpaceView)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
|
@ -138,7 +139,7 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
spCloneRoles, err := h.Store.Space.GetRoles(ctx, model.CloneID)
|
spCloneRoles, err := h.Store.Space.GetPermissions(ctx, model.CloneID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
h.Runtime.Log.Error(method, err)
|
h.Runtime.Log.Error(method, err)
|
||||||
|
@ -147,10 +148,9 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if model.CopyPermission {
|
if model.CopyPermission {
|
||||||
for _, r := range spCloneRoles {
|
for _, r := range spCloneRoles {
|
||||||
r.RefID = uniqueid.Generate()
|
r.RefID = sp.RefID
|
||||||
r.LabelID = sp.RefID
|
|
||||||
|
|
||||||
err = h.Store.Space.AddRole(ctx, r)
|
err = h.Store.Space.AddPermission(ctx, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
|
@ -279,9 +279,9 @@ func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
|
||||||
method := "Get"
|
method := "Get"
|
||||||
ctx := domain.GetRequestContext(r)
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
id := request.Param(r, "folderID")
|
id := request.Param(r, "spaceID")
|
||||||
if len(id) == 0 {
|
if len(id) == 0 {
|
||||||
response.WriteMissingDataError(w, method, "folderID")
|
response.WriteMissingDataError(w, method, "spaceID")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,9 +349,9 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
folderID := request.Param(r, "folderID")
|
spaceID := request.Param(r, "spaceID")
|
||||||
if len(folderID) == 0 {
|
if len(spaceID) == 0 {
|
||||||
response.WriteMissingDataError(w, method, "folderID")
|
response.WriteMissingDataError(w, method, "spaceID")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,7 +377,7 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sp.RefID = folderID
|
sp.RefID = spaceID
|
||||||
|
|
||||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -401,7 +401,7 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
response.WriteJSON(w, sp)
|
response.WriteJSON(w, sp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove moves documents to another folder before deleting it
|
// Remove moves documents to another space before deleting it
|
||||||
func (h *Handler) Remove(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) Remove(w http.ResponseWriter, r *http.Request) {
|
||||||
method := "space.Remove"
|
method := "space.Remove"
|
||||||
ctx := domain.GetRequestContext(r)
|
ctx := domain.GetRequestContext(r)
|
||||||
|
@ -416,9 +416,9 @@ func (h *Handler) Remove(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := request.Param(r, "folderID")
|
id := request.Param(r, "spaceID")
|
||||||
if len(id) == 0 {
|
if len(id) == 0 {
|
||||||
response.WriteMissingDataError(w, method, "folderID")
|
response.WriteMissingDataError(w, method, "spaceID")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,14 +436,6 @@ func (h *Handler) Remove(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
err = h.Store.Document.MoveDocumentSpace(ctx, id, move)
|
err = h.Store.Document.MoveDocumentSpace(ctx, id, move)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
|
@ -452,7 +444,15 @@ func (h *Handler) Remove(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.Store.Space.MoveSpaceRoles(ctx, id, move)
|
_, 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
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = h.Store.Space.DeletePermissions(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
|
@ -490,9 +490,9 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := request.Param(r, "folderID")
|
id := request.Param(r, "spaceID")
|
||||||
if len(id) == 0 {
|
if len(id) == 0 {
|
||||||
response.WriteMissingDataError(w, method, "folderID")
|
response.WriteMissingDataError(w, method, "spaceID")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,7 +512,7 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = h.Store.Space.DeleteSpaceRoles(ctx, id)
|
_, err = h.Store.Space.DeletePermissions(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
|
@ -545,9 +545,9 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
id := request.Param(r, "folderID")
|
id := request.Param(r, "spaceID")
|
||||||
if len(id) == 0 {
|
if len(id) == 0 {
|
||||||
response.WriteMissingDataError(w, method, "folderID")
|
response.WriteMissingDataError(w, method, "spaceID")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,8 +586,8 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We compare new permisions to what we had before.
|
// We compare new permisions to what we had before.
|
||||||
// Why? So we can send out folder invitation emails.
|
// Why? So we can send out space invitation emails.
|
||||||
previousRoles, err := h.Store.Space.GetRoles(ctx, id)
|
previousRoles, err := h.Store.Space.GetPermissions(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
|
@ -599,10 +599,10 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
||||||
previousRoleUsers := make(map[string]bool)
|
previousRoleUsers := make(map[string]bool)
|
||||||
|
|
||||||
for _, v := range previousRoles {
|
for _, v := range previousRoles {
|
||||||
previousRoleUsers[v.UserID] = true
|
previousRoleUsers[v.WhoID] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Who is sharing this folder?
|
// Who is sharing this space?
|
||||||
inviter, err := h.Store.User.Get(ctx, ctx.UserID)
|
inviter, err := h.Store.User.Get(ctx, ctx.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
|
@ -611,8 +611,8 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nuke all previous permissions for this folder
|
// Nuke all previous permissions for this space
|
||||||
_, err = h.Store.Space.DeleteSpaceRoles(ctx, id)
|
_, err = h.Store.Space.DeletePermissions(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
|
@ -626,44 +626,40 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
url := ctx.GetAppURL(fmt.Sprintf("s/%s/%s", sp.RefID, stringutil.MakeSlug(sp.Name)))
|
url := ctx.GetAppURL(fmt.Sprintf("s/%s/%s", sp.RefID, stringutil.MakeSlug(sp.Name)))
|
||||||
|
|
||||||
for _, role := range model.Roles {
|
for _, perm := range model.Permissions {
|
||||||
role.OrgID = ctx.OrgID
|
perm.OrgID = ctx.OrgID
|
||||||
role.LabelID = id
|
perm.RefID = id
|
||||||
|
|
||||||
// Ensure the folder owner always has access!
|
// Ensure the space owner always has access!
|
||||||
if role.UserID == ctx.UserID {
|
if perm.WhoID == ctx.UserID {
|
||||||
me = true
|
me = true
|
||||||
role.CanView = true
|
|
||||||
role.CanEdit = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(role.UserID) == 0 && (role.CanView || role.CanEdit) {
|
if len(perm.WhoID) == 0 {
|
||||||
hasEveryoneRole = true
|
hasEveryoneRole = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only persist if there is a role!
|
// Only persist if there is a role!
|
||||||
if role.CanView || role.CanEdit {
|
if perm.Action == "TBC" {
|
||||||
roleID := uniqueid.Generate()
|
err = h.Store.Space.AddPermission(ctx, perm)
|
||||||
role.RefID = roleID
|
|
||||||
err = h.Store.Space.AddRole(ctx, role)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.Runtime.Log.Error("add role", err)
|
h.Runtime.Log.Error("add role", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
roleCount++
|
roleCount++
|
||||||
|
|
||||||
// We send out folder invitation emails to those users
|
// We send out space invitation emails to those users
|
||||||
// that have *just* been given permissions.
|
// that have *just* been given permissions.
|
||||||
if _, isExisting := previousRoleUsers[role.UserID]; !isExisting {
|
if _, isExisting := previousRoleUsers[perm.WhoID]; !isExisting {
|
||||||
|
|
||||||
// we skip 'everyone' (user id != empty string)
|
// we skip 'everyone' (user id != empty string)
|
||||||
if len(role.UserID) > 0 {
|
if len(perm.WhoID) > 0 {
|
||||||
var existingUser user.User
|
var existingUser user.User
|
||||||
existingUser, err = h.Store.User.Get(ctx, role.UserID)
|
existingUser, err = h.Store.User.Get(ctx, perm.WhoID)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
mailer := mail.Mailer{Runtime: h.Runtime, Store: h.Store, Context: ctx}
|
mailer := mail.Mailer{Runtime: h.Runtime, Store: h.Store, Context: ctx}
|
||||||
go mailer.ShareFolderExistingUser(existingUser.Email, inviter.Fullname(), url, sp.Name, model.Message)
|
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))
|
h.Runtime.Log.Info(fmt.Sprintf("%s is sharing space %s with existing user %s", inviter.Email, sp.Name, existingUser.Email))
|
||||||
} else {
|
} else {
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
|
@ -675,16 +671,16 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Do we need to ensure permissions for space owner when shared?
|
// Do we need to ensure permissions for space owner when shared?
|
||||||
if !me {
|
if !me {
|
||||||
role := space.Role{}
|
perm := space.Permission{}
|
||||||
role.LabelID = id
|
perm.OrgID = ctx.OrgID
|
||||||
role.OrgID = ctx.OrgID
|
perm.Who = "user"
|
||||||
role.UserID = ctx.UserID
|
perm.WhoID = ctx.UserID
|
||||||
role.CanEdit = true
|
perm.Scope = "object"
|
||||||
role.CanView = true
|
perm.Location = "space"
|
||||||
roleID := uniqueid.Generate()
|
perm.RefID = id
|
||||||
role.RefID = roleID
|
perm.Action = "" // we send array for actions below
|
||||||
|
|
||||||
err = h.Store.Space.AddRole(ctx, role)
|
err = h.Store.Space.AddPermission(ctx, perm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
|
@ -692,7 +688,7 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark up folder type as either public, private or restricted access.
|
// Mark up space type as either public, private or restricted access.
|
||||||
if hasEveryoneRole {
|
if hasEveryoneRole {
|
||||||
sp.Type = space.ScopePublic
|
sp.Type = space.ScopePublic
|
||||||
} else {
|
} else {
|
||||||
|
@ -718,28 +714,52 @@ func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
||||||
response.WriteEmpty(w)
|
response.WriteEmpty(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPermissions returns user permissions for the requested folder.
|
// GetPermissions returns permissions for the requested space, for all users.
|
||||||
func (h *Handler) GetPermissions(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) GetPermissions(w http.ResponseWriter, r *http.Request) {
|
||||||
method := "space.GetPermissions"
|
method := "space.GetPermissions"
|
||||||
ctx := domain.GetRequestContext(r)
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
folderID := request.Param(r, "folderID")
|
spaceID := request.Param(r, "spaceID")
|
||||||
if len(folderID) == 0 {
|
if len(spaceID) == 0 {
|
||||||
response.WriteMissingDataError(w, method, "folderID")
|
response.WriteMissingDataError(w, method, "spaceID")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
roles, err := h.Store.Space.GetRoles(ctx, folderID)
|
perms, err := h.Store.Space.GetPermissions(ctx, spaceID)
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(roles) == 0 {
|
if len(perms) == 0 {
|
||||||
roles = []space.Role{}
|
perms = []space.Permission{}
|
||||||
}
|
}
|
||||||
|
|
||||||
response.WriteJSON(w, roles)
|
response.WriteJSON(w, perms)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserPermissions returns permissions for the requested space, for current user.
|
||||||
|
func (h *Handler) GetUserPermissions(w http.ResponseWriter, r *http.Request) {
|
||||||
|
method := "space.GetUserPermissions"
|
||||||
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
|
spaceID := request.Param(r, "spaceID")
|
||||||
|
if len(spaceID) == 0 {
|
||||||
|
response.WriteMissingDataError(w, method, "spaceID")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
perms, err := h.Store.Space.GetUserPermissions(ctx, spaceID)
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
response.WriteServerError(w, method, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(perms) == 0 {
|
||||||
|
perms = []space.Permission{}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteJSON(w, perms)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AcceptInvitation records the fact that a user has completed space onboard process.
|
// AcceptInvitation records the fact that a user has completed space onboard process.
|
||||||
|
@ -748,9 +768,9 @@ func (h *Handler) AcceptInvitation(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := domain.GetRequestContext(r)
|
ctx := domain.GetRequestContext(r)
|
||||||
ctx.Subdomain = organization.GetSubdomainFromHost(r)
|
ctx.Subdomain = organization.GetSubdomainFromHost(r)
|
||||||
|
|
||||||
folderID := request.Param(r, "folderID")
|
spaceID := request.Param(r, "spaceID")
|
||||||
if len(folderID) == 0 {
|
if len(spaceID) == 0 {
|
||||||
response.WriteMissingDataError(w, method, "folderID")
|
response.WriteMissingDataError(w, method, "spaceID")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -831,14 +851,14 @@ func (h *Handler) AcceptInvitation(w http.ResponseWriter, r *http.Request) {
|
||||||
response.WriteJSON(w, u)
|
response.WriteJSON(w, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invite sends users folder invitation emails.
|
// Invite sends users space invitation emails.
|
||||||
func (h *Handler) Invite(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) Invite(w http.ResponseWriter, r *http.Request) {
|
||||||
method := "space.Invite"
|
method := "space.Invite"
|
||||||
ctx := domain.GetRequestContext(r)
|
ctx := domain.GetRequestContext(r)
|
||||||
|
|
||||||
id := request.Param(r, "folderID")
|
id := request.Param(r, "spaceID")
|
||||||
if len(id) == 0 {
|
if len(id) == 0 {
|
||||||
response.WriteMissingDataError(w, method, "folderID")
|
response.WriteMissingDataError(w, method, "spaceID")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -917,6 +937,7 @@ func (h *Handler) Invite(w http.ResponseWriter, r *http.Request) {
|
||||||
a.OrgID = ctx.OrgID
|
a.OrgID = ctx.OrgID
|
||||||
a.Admin = false
|
a.Admin = false
|
||||||
a.Editor = false
|
a.Editor = false
|
||||||
|
a.Users = false
|
||||||
a.Active = true
|
a.Active = true
|
||||||
accountID := uniqueid.Generate()
|
accountID := uniqueid.Generate()
|
||||||
a.RefID = accountID
|
a.RefID = accountID
|
||||||
|
@ -931,18 +952,18 @@ func (h *Handler) Invite(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure they have space roles
|
// Ensure they have space roles
|
||||||
h.Store.Space.DeleteUserSpaceRoles(ctx, sp.RefID, u.RefID)
|
h.Store.Space.DeleteUserPermissions(ctx, sp.RefID, u.RefID)
|
||||||
|
|
||||||
role := space.Role{}
|
perm := space.Permission{}
|
||||||
role.LabelID = sp.RefID
|
perm.OrgID = sp.OrgID
|
||||||
role.OrgID = ctx.OrgID
|
perm.Who = "user"
|
||||||
role.UserID = u.RefID
|
perm.WhoID = u.RefID
|
||||||
role.CanEdit = false
|
perm.Scope = "object"
|
||||||
role.CanView = true
|
perm.Location = "space"
|
||||||
roleID := uniqueid.Generate()
|
perm.RefID = sp.RefID
|
||||||
role.RefID = roleID
|
perm.Action = "" // we send array for actions below
|
||||||
|
|
||||||
err = h.Store.Space.AddRole(ctx, role)
|
err = h.Store.Space.AddPermissions(ctx, perm, space.SpaceView)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
response.WriteServerError(w, method, err)
|
response.WriteServerError(w, method, err)
|
||||||
|
@ -952,7 +973,7 @@ func (h *Handler) Invite(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
url := ctx.GetAppURL(fmt.Sprintf("s/%s/%s", sp.RefID, stringutil.MakeSlug(sp.Name)))
|
url := ctx.GetAppURL(fmt.Sprintf("s/%s/%s", sp.RefID, stringutil.MakeSlug(sp.Name)))
|
||||||
mailer := mail.Mailer{Runtime: h.Runtime, Store: h.Store, Context: ctx}
|
mailer := mail.Mailer{Runtime: h.Runtime, Store: h.Store, Context: ctx}
|
||||||
go mailer.ShareFolderExistingUser(email, inviter.Fullname(), url, sp.Name, model.Message)
|
go mailer.ShareSpaceExistingUser(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, email))
|
h.Runtime.Log.Info(fmt.Sprintf("%s is sharing space %s with existing user %s", inviter.Email, sp.Name, email))
|
||||||
} else {
|
} else {
|
||||||
|
@ -973,7 +994,7 @@ func (h *Handler) Invite(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We ensure that the folder is marked as restricted as a minimum!
|
// We ensure that the space is marked as restricted as a minimum!
|
||||||
if len(model.Recipients) > 0 && sp.Type == space.ScopePrivate {
|
if len(model.Recipients) > 0 && sp.Type == space.ScopePrivate {
|
||||||
sp.Type = space.ScopeRestricted
|
sp.Type = space.ScopeRestricted
|
||||||
|
|
||||||
|
|
|
@ -184,109 +184,98 @@ func (s Scope) Delete(ctx domain.RequestContext, id string) (rows int64, err err
|
||||||
return b.DeleteConstrained(ctx.Transaction, "label", ctx.OrgID, id)
|
return b.DeleteConstrained(ctx.Transaction, "label", ctx.OrgID, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddRole inserts the given record into the labelrole database table.
|
// AddPermission inserts the given record into the labelrole database table.
|
||||||
func (s Scope) AddRole(ctx domain.RequestContext, r space.Role) (err error) {
|
func (s Scope) AddPermission(ctx domain.RequestContext, r space.Permission) (err error) {
|
||||||
r.Created = time.Now().UTC()
|
r.Created = time.Now().UTC()
|
||||||
r.Revised = time.Now().UTC()
|
|
||||||
|
|
||||||
stmt, err := ctx.Transaction.Preparex("INSERT INTO labelrole (refid, labelid, orgid, userid, canview, canedit, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
|
stmt, err := ctx.Transaction.Preparex("INSERT INTO labelrole (orgid, who, whoid, action, scope, location, refid, created) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
|
||||||
defer streamutil.Close(stmt)
|
defer streamutil.Close(stmt)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "unable to prepare insert for space role")
|
err = errors.Wrap(err, "unable to prepare insert for space permission")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = stmt.Exec(r.RefID, r.LabelID, r.OrgID, r.UserID, r.CanView, r.CanEdit, r.Created, r.Revised)
|
_, err = stmt.Exec(r.OrgID, r.Who, r.WhoID, r.Action, r.Scope, r.Location, r.RefID, r.Created)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "unable to execute insert for space role")
|
err = errors.Wrap(err, "unable to execute insert for space permission")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRoles returns a slice of labelrole records, for the given labelID in the client's organization, grouped by user.
|
// AddPermissions inserts records into permission database table, one per action.
|
||||||
func (s Scope) GetRoles(ctx domain.RequestContext, labelID string) (r []space.Role, err error) {
|
func (s Scope) AddPermissions(ctx domain.RequestContext, r space.Permission, actions ...space.PermissionAction) (err error) {
|
||||||
query := `SELECT id, refid, labelid, orgid, userid, canview, canedit, created, revised FROM labelrole WHERE orgid=? AND labelid=?` // was + "GROUP BY userid"
|
for _, a := range actions {
|
||||||
|
r.Action = string(a)
|
||||||
err = s.Runtime.Db.Select(&r, query, ctx.OrgID, labelID)
|
s.AddPermission(ctx, r)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute select for space roles %s", labelID))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserRoles returns a slice of role records, for both the client's user and organization, and
|
// GetUserPermissions returns space permissions for user.
|
||||||
// those space roles that exist for all users in the client's organization.
|
// Context is used to for user ID.
|
||||||
func (s Scope) GetUserRoles(ctx domain.RequestContext) (r []space.Role, err error) {
|
func (s Scope) GetUserPermissions(ctx domain.RequestContext, spaceID string) (r []space.Permission, err error) {
|
||||||
err = s.Runtime.Db.Select(&r, `
|
err = s.Runtime.Db.Select(&r, `
|
||||||
SELECT id, refid, labelid, orgid, userid, canview, canedit, created, revised FROM labelrole WHERE orgid=? and userid=?
|
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='')
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT id, refid, labelid, orgid, userid, canview, canedit, created, revised FROM labelrole WHERE orgid=? AND userid=''`,
|
SELECT p.id, p.orgid, p.who, p.whoid, p.action, p.scope, p.location, p.refid
|
||||||
ctx.OrgID, ctx.UserID, ctx.OrgID)
|
FROM permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.location='space' AND refid=?
|
||||||
|
AND p.who='role' AND (r.userid=? OR r.userid='')`,
|
||||||
|
ctx.OrgID, spaceID, ctx.UserID, ctx.OrgID, spaceID, ctx.OrgID)
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute select for user space roles %s", ctx.UserID))
|
err = errors.Wrap(err, fmt.Sprintf("unable to execute select user permissions %s", ctx.UserID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRole deletes the labelRoleID record from the labelrole table.
|
// GetPermissions returns space permissions for all users.
|
||||||
func (s Scope) DeleteRole(ctx domain.RequestContext, roleID string) (rows int64, err error) {
|
func (s Scope) GetPermissions(ctx domain.RequestContext, spaceID string) (r []space.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='')
|
||||||
|
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='space' AND p.refid=?
|
||||||
|
AND p.who='role' AND (r.userid=? OR r.userid='')`,
|
||||||
|
ctx.OrgID, spaceID, ctx.UserID, ctx.OrgID, spaceID, ctx.OrgID)
|
||||||
|
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, fmt.Sprintf("unable to execute select space permissions %s", ctx.UserID))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeletePermissions removes records from permissions table for given space ID.
|
||||||
|
func (s Scope) DeletePermissions(ctx domain.RequestContext, spaceID string) (rows int64, err error) {
|
||||||
b := mysql.BaseQuery{}
|
b := mysql.BaseQuery{}
|
||||||
|
|
||||||
sql := fmt.Sprintf("DELETE FROM labelrole WHERE orgid='%s' AND refid='%s'", ctx.OrgID, roleID)
|
sql := fmt.Sprintf("DELETE FROM permission WHERE orgid='%s' AND location='space' AND refid='%s'",
|
||||||
|
ctx.OrgID, spaceID)
|
||||||
|
|
||||||
return b.DeleteWhere(ctx.Transaction, sql)
|
return b.DeleteWhere(ctx.Transaction, sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteSpaceRoles deletes records from the labelrole table which have the given space ID.
|
// DeleteUserPermissions removes all roles for the specified user, for the specified space.
|
||||||
func (s Scope) DeleteSpaceRoles(ctx domain.RequestContext, spaceID string) (rows int64, err error) {
|
func (s Scope) DeleteUserPermissions(ctx domain.RequestContext, spaceID, userID string) (rows int64, err error) {
|
||||||
b := mysql.BaseQuery{}
|
b := mysql.BaseQuery{}
|
||||||
|
|
||||||
sql := fmt.Sprintf("DELETE FROM labelrole WHERE orgid='%s' AND labelid='%s'", ctx.OrgID, spaceID)
|
sql := fmt.Sprintf("DELETE FROM permission WHERE orgid='%s' AND location='space' AND refid='%s' who='user' AND whoid='%s'",
|
||||||
|
|
||||||
return b.DeleteWhere(ctx.Transaction, sql)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteUserSpaceRoles removes all roles for the specified user, for the specified space.
|
|
||||||
func (s Scope) DeleteUserSpaceRoles(ctx domain.RequestContext, spaceID, userID string) (rows int64, err error) {
|
|
||||||
b := mysql.BaseQuery{}
|
|
||||||
|
|
||||||
sql := fmt.Sprintf("DELETE FROM labelrole WHERE orgid='%s' AND labelid='%s' AND userid='%s'",
|
|
||||||
ctx.OrgID, spaceID, userID)
|
ctx.OrgID, spaceID, userID)
|
||||||
|
|
||||||
return b.DeleteWhere(ctx.Transaction, sql)
|
return b.DeleteWhere(ctx.Transaction, sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MoveSpaceRoles changes the space ID for space role records from previousLabel to newLabel.
|
|
||||||
func (s Scope) MoveSpaceRoles(ctx domain.RequestContext, previousLabel, newLabel string) (err error) {
|
|
||||||
stmt, err := ctx.Transaction.Preparex("UPDATE labelrole SET labelid=? WHERE labelid=? AND orgid=?")
|
|
||||||
defer streamutil.Close(stmt)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
err = errors.Wrap(err, fmt.Sprintf("unable to prepare move space roles for label %s", previousLabel))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = stmt.Exec(newLabel, previousLabel, ctx.OrgID)
|
|
||||||
if err != nil {
|
|
||||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute move space roles for label %s", previousLabel))
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,11 +17,12 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
"github.com/documize/community/domain"
|
"github.com/documize/community/domain"
|
||||||
|
"github.com/documize/community/model/space"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CanViewSpace returns if the user has permission to view the given spaceID.
|
// CanViewSpace returns if the user has permission to view the given spaceID.
|
||||||
func CanViewSpace(ctx domain.RequestContext, s domain.Store, spaceID string) (hasPermission bool) {
|
func CanViewSpace(ctx domain.RequestContext, s domain.Store, spaceID string) bool {
|
||||||
roles, err := s.Space.GetRoles(ctx, spaceID)
|
roles, err := s.Space.GetUserPermissions(ctx, spaceID)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
|
@ -30,27 +31,8 @@ func CanViewSpace(ctx domain.RequestContext, s domain.Store, spaceID string) (ha
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
if role.LabelID == spaceID && (role.CanView || role.CanEdit) {
|
if role.RefID == spaceID && role.Location == "space" && role.Scope == "object" &&
|
||||||
return true
|
space.HasPermission(role.Action, space.SpaceView, space.SpaceManage, space.SpaceOwner) {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// CanViewSpaceDocuments returns if the user has permission to view a document within the specified space.
|
|
||||||
func CanViewSpaceDocuments(ctx domain.RequestContext, s domain.Store, spaceID string) (hasPermission bool) {
|
|
||||||
roles, err := s.Space.GetRoles(ctx, spaceID)
|
|
||||||
if err == sql.ErrNoRows {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, role := range roles {
|
|
||||||
if role.LabelID == spaceID && (role.CanView || role.CanEdit) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,33 +24,10 @@ import (
|
||||||
"github.com/documize/community/model/user"
|
"github.com/documize/community/model/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
// addSpace prepares and creates space record.
|
// Invite new user to a space that someone has shared with them.
|
||||||
func addSpace(ctx domain.RequestContext, s *domain.Store, sp space.Space) (err error) {
|
|
||||||
sp.Type = space.ScopePrivate
|
|
||||||
sp.UserID = ctx.UserID
|
|
||||||
|
|
||||||
err = s.Space.Add(ctx, sp)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
role := space.Role{}
|
|
||||||
role.LabelID = sp.RefID
|
|
||||||
role.OrgID = sp.OrgID
|
|
||||||
role.UserID = ctx.UserID
|
|
||||||
role.CanEdit = true
|
|
||||||
role.CanView = true
|
|
||||||
role.RefID = uniqueid.Generate()
|
|
||||||
|
|
||||||
err = s.Space.AddRole(ctx, role)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invite new user to a folder that someone has shared with them.
|
|
||||||
// We create the user account with default values and then take them
|
// We create the user account with default values and then take them
|
||||||
// through a welcome process designed to capture profile data.
|
// through a welcome process designed to capture profile data.
|
||||||
// We add them to the organization and grant them view-only folder access.
|
// We add them to the organization and grant them view-only space access.
|
||||||
func inviteNewUserToSharedSpace(ctx domain.RequestContext, rt *env.Runtime, s *domain.Store, email string, invitedBy user.User,
|
func inviteNewUserToSharedSpace(ctx domain.RequestContext, rt *env.Runtime, s *domain.Store, email string, invitedBy user.User,
|
||||||
baseURL string, sp space.Space, invitationMessage string) (err error) {
|
baseURL string, sp space.Space, invitationMessage string) (err error) {
|
||||||
|
|
||||||
|
@ -75,25 +52,25 @@ func inviteNewUserToSharedSpace(ctx domain.RequestContext, rt *env.Runtime, s *d
|
||||||
a.OrgID = ctx.OrgID
|
a.OrgID = ctx.OrgID
|
||||||
a.Admin = false
|
a.Admin = false
|
||||||
a.Editor = false
|
a.Editor = false
|
||||||
|
a.Users = false
|
||||||
a.Active = true
|
a.Active = true
|
||||||
accountID := uniqueid.Generate()
|
a.RefID = uniqueid.Generate()
|
||||||
a.RefID = accountID
|
|
||||||
|
|
||||||
err = s.Account.Add(ctx, a)
|
err = s.Account.Add(ctx, a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
role := space.Role{}
|
perm := space.Permission{}
|
||||||
role.LabelID = sp.RefID
|
perm.OrgID = sp.OrgID
|
||||||
role.OrgID = ctx.OrgID
|
perm.Who = "user"
|
||||||
role.UserID = userID
|
perm.WhoID = userID
|
||||||
role.CanEdit = false
|
perm.Scope = "object"
|
||||||
role.CanView = true
|
perm.Location = "space"
|
||||||
roleID := uniqueid.Generate()
|
perm.RefID = sp.RefID
|
||||||
role.RefID = roleID
|
perm.Action = "" // we send array for actions below
|
||||||
|
|
||||||
err = s.Space.AddRole(ctx, role)
|
err = s.Space.AddPermissions(ctx, perm, space.SpaceView)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -101,7 +78,7 @@ func inviteNewUserToSharedSpace(ctx domain.RequestContext, rt *env.Runtime, s *d
|
||||||
mailer := mail.Mailer{Runtime: rt, Store: s, Context: ctx}
|
mailer := mail.Mailer{Runtime: rt, Store: s, Context: ctx}
|
||||||
|
|
||||||
url := fmt.Sprintf("%s/%s", baseURL, u.Salt)
|
url := fmt.Sprintf("%s/%s", baseURL, u.Salt)
|
||||||
go mailer.ShareFolderNewUser(u.Email, invitedBy.Fullname(), url, sp.Name, invitationMessage)
|
go mailer.ShareSpaceNewUser(u.Email, invitedBy.Fullname(), url, sp.Name, invitationMessage)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package space
|
package space
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/documize/community/core/uniqueid"
|
"github.com/documize/community/core/uniqueid"
|
||||||
|
@ -39,17 +38,19 @@ func TestSpace(t *testing.T) {
|
||||||
t.Error("failed to add sp space")
|
t.Error("failed to add sp space")
|
||||||
}
|
}
|
||||||
|
|
||||||
r.RefID = uniqueid.Generate()
|
perm := space.Permission{}
|
||||||
r.LabelID = spaceID
|
perm.OrgID = ctx.OrgID
|
||||||
r.OrgID = ctx.OrgID
|
perm.Who = "user"
|
||||||
r.UserID = "testAddSpace"
|
perm.WhoID = ctx.UserID
|
||||||
r.CanView = true
|
perm.Scope = "object"
|
||||||
r.CanEdit = true
|
perm.Location = "space"
|
||||||
|
perm.RefID = spaceID
|
||||||
|
perm.Action = "" // we send array for actions below
|
||||||
|
|
||||||
err = s.Space.AddRole(ctx, r)
|
err = s.Space.AddPermissions(ctx, perm, space.SpaceOwner, space.SpaceManage, space.SpaceView)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
t.Error("failed to add role r")
|
t.Error("failed to add permission")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Transaction.Commit()
|
ctx.Transaction.Commit()
|
||||||
|
@ -104,17 +105,19 @@ func TestSpace(t *testing.T) {
|
||||||
t.Error("failed to add sp2")
|
t.Error("failed to add sp2")
|
||||||
}
|
}
|
||||||
|
|
||||||
r2.RefID = uniqueid.Generate()
|
perm := space.Permission{}
|
||||||
r2.LabelID = spaceID2
|
perm.OrgID = ctx.OrgID
|
||||||
r2.OrgID = ctx.OrgID
|
perm.Who = "user"
|
||||||
r2.UserID = ctx.UserID
|
perm.WhoID = ctx.UserID
|
||||||
r2.CanView = true
|
perm.Scope = "object"
|
||||||
r2.CanEdit = true
|
perm.Location = "space"
|
||||||
|
perm.RefID = spaceID2
|
||||||
|
perm.Action = "" // we send array for actions below
|
||||||
|
|
||||||
err = s.Space.AddRole(ctx, r2)
|
err = s.Space.AddPermissions(ctx, perm, space.SpaceOwner, space.SpaceManage, space.SpaceView)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
t.Error("failed to add role")
|
t.Error("failed to add permission")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Transaction.Commit()
|
ctx.Transaction.Commit()
|
||||||
|
@ -171,22 +174,24 @@ func TestSpace(t *testing.T) {
|
||||||
t.Run("Add Role", func(t *testing.T) {
|
t.Run("Add Role", func(t *testing.T) {
|
||||||
ctx.Transaction, err = rt.Db.Beginx()
|
ctx.Transaction, err = rt.Db.Beginx()
|
||||||
|
|
||||||
r3.CanView = true
|
perm := space.Permission{}
|
||||||
r3.CanEdit = true
|
perm.OrgID = ctx.OrgID
|
||||||
r3.RefID = uniqueid.Generate()
|
perm.Who = "user"
|
||||||
r3.LabelID = spaceID
|
perm.WhoID = ctx.UserID
|
||||||
r3.OrgID = ctx.OrgID
|
perm.Scope = "object"
|
||||||
r3.UserID = "testAddRole"
|
perm.Location = "space"
|
||||||
|
perm.RefID = spaceID
|
||||||
|
perm.Action = "" // we send array for actions below
|
||||||
|
|
||||||
err = s.Space.AddRole(ctx, r3)
|
err = s.Space.AddPermissions(ctx, perm, space.DocumentAdd, space.DocumentDelete, space.DocumentMove)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Transaction.Rollback()
|
ctx.Transaction.Rollback()
|
||||||
t.Error("failed to add role")
|
t.Error("failed to add permission")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Transaction.Commit()
|
ctx.Transaction.Commit()
|
||||||
|
|
||||||
roles, err := s.Space.GetRoles(ctx, spaceID)
|
roles, err := s.Space.GetUserPermissions(ctx, spaceID)
|
||||||
if err != nil || roles == nil {
|
if err != nil || roles == nil {
|
||||||
t.Error("Could not get any roles")
|
t.Error("Could not get any roles")
|
||||||
return
|
return
|
||||||
|
@ -194,61 +199,16 @@ func TestSpace(t *testing.T) {
|
||||||
// TODO: could we Verify the role was added with the if r3.UserID == Returned.UserID?
|
// TODO: could we Verify the role was added with the if r3.UserID == Returned.UserID?
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Get User Roles", func(t *testing.T) {
|
t.Run("Get User Permissions", func(t *testing.T) {
|
||||||
userRoles, err := s.Space.GetUserRoles(ctx)
|
userRoles, err := s.Space.GetUserPermissions(ctx, spaceID)
|
||||||
if err != nil || userRoles == nil {
|
if err != nil || userRoles == nil {
|
||||||
t.Error("failed to get user roles")
|
t.Error("failed to get user roles")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Move space Roles", func(t *testing.T) {
|
// teardown
|
||||||
ctx.Transaction, err = rt.Db.Beginx()
|
t.Run("Delete space", func(t *testing.T) {
|
||||||
err := s.Space.MoveSpaceRoles(ctx, spaceID, spaceID2)
|
|
||||||
if err != nil {
|
|
||||||
ctx.Transaction.Rollback()
|
|
||||||
t.Error("failed to move space roles")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Transaction.Commit()
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Delete Role", func(t *testing.T) {
|
|
||||||
ctx.Transaction, err = rt.Db.Beginx()
|
|
||||||
rowsDeleted, err := s.Space.DeleteRole(ctx, r3.RefID)
|
|
||||||
if err != nil || rowsDeleted == 0 {
|
|
||||||
ctx.Transaction.Rollback()
|
|
||||||
t.Error("failed to delete roles")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Transaction.Commit()
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Delete space Roles", func(t *testing.T) {
|
|
||||||
ctx.Transaction, err = rt.Db.Beginx()
|
|
||||||
_, err := s.Space.DeleteSpaceRoles(ctx, spaceID)
|
|
||||||
if err != nil && err != sql.ErrNoRows {
|
|
||||||
ctx.Transaction.Rollback()
|
|
||||||
t.Error("failed to delete space roles")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Transaction.Commit()
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Delete user space Roles", func(t *testing.T) {
|
|
||||||
ctx.Transaction, err = rt.Db.Beginx()
|
|
||||||
_, err := s.Space.DeleteUserSpaceRoles(ctx, spaceID2, ctx.UserID)
|
|
||||||
if err != nil && err != sql.ErrNoRows {
|
|
||||||
ctx.Transaction.Rollback()
|
|
||||||
t.Error("failed to delete user space roles")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Transaction.Commit()
|
|
||||||
})
|
|
||||||
|
|
||||||
//Delete spaces last, otherwise tests may fail
|
|
||||||
|
|
||||||
t.Run("Delete Space", func(t *testing.T) {
|
|
||||||
ctx.Transaction, err = rt.Db.Beginx()
|
ctx.Transaction, err = rt.Db.Beginx()
|
||||||
|
|
||||||
_, err = s.Space.Delete(ctx, spaceID)
|
_, err = s.Space.Delete(ctx, spaceID)
|
||||||
|
@ -261,11 +221,7 @@ func TestSpace(t *testing.T) {
|
||||||
ctx.Transaction.Commit()
|
ctx.Transaction.Commit()
|
||||||
})
|
})
|
||||||
|
|
||||||
//
|
t.Run("Delete space 2", func(t *testing.T) {
|
||||||
// teardown code goes here
|
|
||||||
//
|
|
||||||
|
|
||||||
t.Run("Delete sp2 Space", func(t *testing.T) {
|
|
||||||
ctx.Transaction, err = rt.Db.Beginx()
|
ctx.Transaction, err = rt.Db.Beginx()
|
||||||
|
|
||||||
_, err = s.Space.Delete(ctx, spaceID2)
|
_, err = s.Space.Delete(ctx, spaceID2)
|
||||||
|
@ -277,15 +233,4 @@ func TestSpace(t *testing.T) {
|
||||||
|
|
||||||
ctx.Transaction.Commit()
|
ctx.Transaction.Commit()
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Delete r Role", func(t *testing.T) {
|
|
||||||
ctx.Transaction, err = rt.Db.Beginx()
|
|
||||||
rowsDeleted, err := s.Space.DeleteRole(ctx, r.RefID)
|
|
||||||
if err != nil || rowsDeleted == 0 {
|
|
||||||
ctx.Transaction.Rollback()
|
|
||||||
t.Error("failed to delete role r in teardown")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Transaction.Commit()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,13 +56,13 @@ type SpaceStorer interface {
|
||||||
ChangeOwner(ctx RequestContext, currentOwner, newOwner string) (err error)
|
ChangeOwner(ctx RequestContext, currentOwner, newOwner string) (err error)
|
||||||
Viewers(ctx RequestContext) (v []space.Viewer, err error)
|
Viewers(ctx RequestContext) (v []space.Viewer, err error)
|
||||||
Delete(ctx RequestContext, id string) (rows int64, err error)
|
Delete(ctx RequestContext, id string) (rows int64, err error)
|
||||||
AddRole(ctx RequestContext, r space.Role) (err error)
|
|
||||||
GetRoles(ctx RequestContext, labelID string) (r []space.Role, err error)
|
AddPermission(ctx RequestContext, r space.Permission) (err error)
|
||||||
GetUserRoles(ctx RequestContext) (r []space.Role, err error)
|
AddPermissions(ctx RequestContext, r space.Permission, actions ...space.PermissionAction) (err error)
|
||||||
DeleteRole(ctx RequestContext, roleID string) (rows int64, err error)
|
GetUserPermissions(ctx RequestContext, spaceID string) (r []space.Permission, err error)
|
||||||
DeleteSpaceRoles(ctx RequestContext, spaceID string) (rows int64, err error)
|
GetPermissions(ctx RequestContext, spaceID string) (r []space.Permission, err error)
|
||||||
DeleteUserSpaceRoles(ctx RequestContext, spaceID, userID string) (rows int64, err error)
|
DeleteUserPermissions(ctx RequestContext, spaceID, userID string) (rows int64, err error)
|
||||||
MoveSpaceRoles(ctx RequestContext, previousLabel, newLabel string) (err error)
|
DeletePermissions(ctx RequestContext, spaceID string) (rows int64, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserStorer defines required methods for user management
|
// UserStorer defines required methods for user management
|
||||||
|
|
|
@ -538,31 +538,6 @@ func (h *Handler) ChangePassword(w http.ResponseWriter, r *http.Request) {
|
||||||
response.WriteEmpty(w)
|
response.WriteEmpty(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserSpacePermissions returns folder permission for authenticated user.
|
|
||||||
func (h *Handler) UserSpacePermissions(w http.ResponseWriter, r *http.Request) {
|
|
||||||
method := "user.UserSpacePermissions"
|
|
||||||
ctx := domain.GetRequestContext(r)
|
|
||||||
|
|
||||||
userID := request.Param(r, "userID")
|
|
||||||
if userID != ctx.UserID {
|
|
||||||
response.WriteForbiddenError(w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
roles, err := h.Store.Space.GetUserRoles(ctx)
|
|
||||||
if err == sql.ErrNoRows {
|
|
||||||
err = nil
|
|
||||||
roles = []space.Role{}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
response.WriteServerError(w, method, err)
|
|
||||||
h.Runtime.Log.Error(method, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
response.WriteJSON(w, roles)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ForgotPassword initiates the change password procedure.
|
// ForgotPassword initiates the change password procedure.
|
||||||
// Generates a reset token and sends email to the user.
|
// Generates a reset token and sends email to the user.
|
||||||
// User has to click link in email and then provide a new password.
|
// User has to click link in email and then provide a new password.
|
||||||
|
|
|
@ -48,8 +48,8 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, AuthMixin, {
|
||||||
this.addTooltip(document.getElementById("delete-documents-button"));
|
this.addTooltip(document.getElementById("delete-documents-button"));
|
||||||
} else {
|
} else {
|
||||||
if (this.get('isFolderOwner')) {
|
if (this.get('isFolderOwner')) {
|
||||||
this.addTooltip(document.getElementById("folder-share-button"));
|
this.addTooltip(document.getElementById("space-delete-button"));
|
||||||
this.addTooltip(document.getElementById("folder-settings-button"));
|
this.addTooltip(document.getElementById("space-settings-button"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -23,7 +23,7 @@ export default Ember.Component.extend(NotifierMixin, {
|
||||||
inviteMessage: '',
|
inviteMessage: '',
|
||||||
|
|
||||||
getDefaultInvitationMessage() {
|
getDefaultInvitationMessage() {
|
||||||
return "Hey there, I am sharing the " + this.folder.get('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.folder.get('name') + " space (in " + this.get("appMeta.title") + ") with you so we can both collaborate on documents.";
|
||||||
},
|
},
|
||||||
|
|
||||||
willRender() {
|
willRender() {
|
||||||
|
@ -67,7 +67,8 @@ export default Ember.Component.extend(NotifierMixin, {
|
||||||
this.set('inviteEmail', '');
|
this.set('inviteEmail', '');
|
||||||
|
|
||||||
this.get('folderService').share(this.folder.get('id'), result).then(() => {
|
this.get('folderService').share(this.folder.get('id'), result).then(() => {
|
||||||
this.showNotification('Shared');
|
this.showNotification('Invietd co-workers');
|
||||||
|
$('#inviteEmail').removeClass('error');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -32,13 +32,22 @@ export default Ember.Component.extend(NotifierMixin, {
|
||||||
let isActive = user.get('active');
|
let isActive = user.get('active');
|
||||||
|
|
||||||
let u = {
|
let u = {
|
||||||
userId: user.get('id'),
|
|
||||||
fullname: user.get('fullname'),
|
fullname: user.get('fullname'),
|
||||||
orgId: this.get('folder.orgId'),
|
orgId: this.get('folder.orgId'),
|
||||||
folderId: this.get('folder.id'),
|
who: 'user',
|
||||||
canEdit: false,
|
whoId: user.get('id'),
|
||||||
canView: false,
|
location: 'space',
|
||||||
canViewPrevious: false
|
scope: 'object',
|
||||||
|
refId: this.get('folder.id'),
|
||||||
|
spaceView: false,
|
||||||
|
spaceManage: false,
|
||||||
|
spaceOwner: false,
|
||||||
|
docAdd: false,
|
||||||
|
docEdit: false,
|
||||||
|
docDelete: false,
|
||||||
|
docMove: false,
|
||||||
|
docCopy: false,
|
||||||
|
docTemplate: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
|
@ -47,12 +56,22 @@ export default Ember.Component.extend(NotifierMixin, {
|
||||||
});
|
});
|
||||||
|
|
||||||
var u = {
|
var u = {
|
||||||
userId: "",
|
|
||||||
fullname: " Everyone",
|
fullname: " Everyone",
|
||||||
orgId: this.get('folder.orgId'),
|
orgId: this.get('folder.orgId'),
|
||||||
folderId: this.get('folder.id'),
|
who: 'user',
|
||||||
canEdit: false,
|
whoId: '',
|
||||||
canView: false
|
location: 'space',
|
||||||
|
scope: 'object',
|
||||||
|
refId: this.get('folder.id'),
|
||||||
|
spaceView: false,
|
||||||
|
spaceManage: false,
|
||||||
|
spaceOwner: false,
|
||||||
|
docAdd: false,
|
||||||
|
docEdit: false,
|
||||||
|
docDelete: false,
|
||||||
|
docMove: false,
|
||||||
|
docCopy: false,
|
||||||
|
docTemplate: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
folderPermissions.pushObject(u);
|
folderPermissions.pushObject(u);
|
||||||
|
@ -111,6 +130,7 @@ export default Ember.Component.extend(NotifierMixin, {
|
||||||
var payload = { Message: message, Roles: data };
|
var payload = { Message: message, Roles: data };
|
||||||
|
|
||||||
this.get('folderService').savePermissions(folder.get('id'), payload).then(() => {
|
this.get('folderService').savePermissions(folder.get('id'), payload).then(() => {
|
||||||
|
this.showNotification('Saved permissions');
|
||||||
});
|
});
|
||||||
|
|
||||||
var hasEveryone = _.find(data, function (permission) {
|
var hasEveryone = _.find(data, function (permission) {
|
||||||
|
@ -128,7 +148,6 @@ export default Ember.Component.extend(NotifierMixin, {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.get('folderService').save(folder).then(function () {
|
this.get('folderService').save(folder).then(function () {
|
||||||
// window.location.href = "/folder/" + folder.get('id') + "/" + folder.get('slug');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
24
gui/app/models/user-permission.js
Normal file
24
gui/app/models/user-permission.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// 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, hasMany } from 'ember-data/relationships';
|
||||||
|
|
||||||
|
export default Model.extend({
|
||||||
|
orgId: attr('string'),
|
||||||
|
who: attr('string'),
|
||||||
|
whoId: attr('string'),
|
||||||
|
action: attr('string'),
|
||||||
|
scope: attr('string'),
|
||||||
|
location: attr('string'),
|
||||||
|
refId: attr('string')
|
||||||
|
});
|
|
@ -10,78 +10,6 @@
|
||||||
// https://documize.com
|
// https://documize.com
|
||||||
|
|
||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
import NotifierMixin from '../../mixins/notifier';
|
|
||||||
|
|
||||||
export default Ember.Controller.extend(NotifierMixin, {
|
export default Ember.Controller.extend({
|
||||||
documentService: Ember.inject.service('document'),
|
|
||||||
folderService: Ember.inject.service('folder'),
|
|
||||||
localStorage: Ember.inject.service('localStorage'),
|
|
||||||
selectedDocuments: [],
|
|
||||||
hasSelectedDocuments: Ember.computed.gt('selectedDocuments.length', 0),
|
|
||||||
queryParams: ['tab'],
|
|
||||||
tab: 'index',
|
|
||||||
|
|
||||||
actions: {
|
|
||||||
onMoveDocument(folder) {
|
|
||||||
let self = this;
|
|
||||||
let documents = this.get('selectedDocuments');
|
|
||||||
|
|
||||||
documents.forEach(function (documentId) {
|
|
||||||
self.get('documentService').getDocument(documentId).then(function (doc) {
|
|
||||||
doc.set('folderId', folder);
|
|
||||||
doc.set('selected', !doc.get('selected'));
|
|
||||||
self.get('documentService').save(doc).then(function () {
|
|
||||||
self.get('target._routerMicrolib').refresh();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.set('selectedDocuments', []);
|
|
||||||
this.send("showNotification", "Moved");
|
|
||||||
},
|
|
||||||
|
|
||||||
onDeleteDocument() {
|
|
||||||
let documents = this.get('selectedDocuments');
|
|
||||||
let self = this;
|
|
||||||
let promises = [];
|
|
||||||
|
|
||||||
documents.forEach(function (document, index) {
|
|
||||||
promises[index] = self.get('documentService').deleteDocument(document);
|
|
||||||
});
|
|
||||||
|
|
||||||
Ember.RSVP.all(promises).then(() => {
|
|
||||||
let documents = this.get('model.documents');
|
|
||||||
documents.forEach(function (document) {
|
|
||||||
document.set('selected', false);
|
|
||||||
});
|
|
||||||
this.set('model.documents', documents);
|
|
||||||
|
|
||||||
this.set('selectedDocuments', []);
|
|
||||||
this.send("showNotification", "Deleted");
|
|
||||||
this.get('target._routerMicrolib').refresh();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onAddSpace(payload) {
|
|
||||||
let self = this;
|
|
||||||
this.showNotification("Added");
|
|
||||||
|
|
||||||
this.get('folderService').add(payload).then(function (newFolder) {
|
|
||||||
self.get('folderService').setCurrentFolder(newFolder);
|
|
||||||
self.transitionToRoute('folder', newFolder.get('id'), newFolder.get('slug'));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onDeleteSpace() {
|
|
||||||
this.get('folderService').delete(this.get('model.folder.id')).then(() => { /* jshint ignore:line */
|
|
||||||
this.showNotification("Deleted");
|
|
||||||
this.get('localStorage').clearSessionItem('folder');
|
|
||||||
this.transitionToRoute('application');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onImport() {
|
|
||||||
this.get('target._routerMicrolib').refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
87
gui/app/pods/folder/index/controller.js
Normal file
87
gui/app/pods/folder/index/controller.js
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
// 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 Ember from 'ember';
|
||||||
|
import NotifierMixin from '../../../mixins/notifier';
|
||||||
|
|
||||||
|
export default Ember.Controller.extend(NotifierMixin, {
|
||||||
|
documentService: Ember.inject.service('document'),
|
||||||
|
folderService: Ember.inject.service('folder'),
|
||||||
|
localStorage: Ember.inject.service('localStorage'),
|
||||||
|
selectedDocuments: [],
|
||||||
|
hasSelectedDocuments: Ember.computed.gt('selectedDocuments.length', 0),
|
||||||
|
queryParams: ['tab'],
|
||||||
|
tab: 'index',
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
onMoveDocument(folder) {
|
||||||
|
let self = this;
|
||||||
|
let documents = this.get('selectedDocuments');
|
||||||
|
|
||||||
|
documents.forEach(function (documentId) {
|
||||||
|
self.get('documentService').getDocument(documentId).then(function (doc) {
|
||||||
|
doc.set('folderId', folder);
|
||||||
|
doc.set('selected', !doc.get('selected'));
|
||||||
|
self.get('documentService').save(doc).then(function () {
|
||||||
|
self.get('target._routerMicrolib').refresh();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.set('selectedDocuments', []);
|
||||||
|
this.send("showNotification", "Moved");
|
||||||
|
},
|
||||||
|
|
||||||
|
onDeleteDocument() {
|
||||||
|
let documents = this.get('selectedDocuments');
|
||||||
|
let self = this;
|
||||||
|
let promises = [];
|
||||||
|
|
||||||
|
documents.forEach(function (document, index) {
|
||||||
|
promises[index] = self.get('documentService').deleteDocument(document);
|
||||||
|
});
|
||||||
|
|
||||||
|
Ember.RSVP.all(promises).then(() => {
|
||||||
|
let documents = this.get('model.documents');
|
||||||
|
documents.forEach(function (document) {
|
||||||
|
document.set('selected', false);
|
||||||
|
});
|
||||||
|
this.set('model.documents', documents);
|
||||||
|
|
||||||
|
this.set('selectedDocuments', []);
|
||||||
|
this.send("showNotification", "Deleted");
|
||||||
|
this.get('target._routerMicrolib').refresh();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onAddSpace(payload) {
|
||||||
|
let self = this;
|
||||||
|
this.showNotification("Added");
|
||||||
|
|
||||||
|
this.get('folderService').add(payload).then(function (newFolder) {
|
||||||
|
self.get('folderService').setCurrentFolder(newFolder);
|
||||||
|
self.transitionToRoute('folder', newFolder.get('id'), newFolder.get('slug'));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onDeleteSpace() {
|
||||||
|
this.get('folderService').delete(this.get('model.folder.id')).then(() => { /* jshint ignore:line */
|
||||||
|
this.showNotification("Deleted");
|
||||||
|
this.get('localStorage').clearSessionItem('folder');
|
||||||
|
this.transitionToRoute('application');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onImport() {
|
||||||
|
this.get('target._routerMicrolib').refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
28
gui/app/pods/folder/index/route.js
Normal file
28
gui/app/pods/folder/index/route.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// 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 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,
|
||||||
|
isEditor: this.modelFor('folder').isEditor,
|
||||||
|
isFolderOwner: this.modelFor('folder').isFolderOwner,
|
||||||
|
folders: this.modelFor('folder').folders,
|
||||||
|
documents: this.modelFor('folder').documents,
|
||||||
|
templates: this.modelFor('folder').templates
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
14
gui/app/pods/folder/index/template.hbs
Normal file
14
gui/app/pods/folder/index/template.hbs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{{#layout/zone-container}}
|
||||||
|
{{#layout/zone-sidebar}}
|
||||||
|
{{folder/sidebar-zone folders=model.folders folder=model.folder isFolderOwner=model.isFolderOwner isEditor=model.isEditor tab=tab
|
||||||
|
onAddSpace=(action 'onAddSpace')}}
|
||||||
|
{{/layout/zone-sidebar}}
|
||||||
|
{{#layout/zone-content}}
|
||||||
|
{{folder/folder-heading folder=model.folder isFolderOwner=model.isFolderOwner isEditor=model.isEditor}}
|
||||||
|
{{folder/folder-toolbar folders=model.folders isFolderOwner=model.isFolderOwner folder=model.folder hasSelectedDocuments=hasSelectedDocuments
|
||||||
|
onDeleteDocument=(action 'onDeleteDocument') onMoveDocument=(action 'onMoveDocument')}}
|
||||||
|
{{folder/documents-list documents=model.documents folders=model.folders folder=model.folder templates=model.templates
|
||||||
|
isFolderOwner=model.isFolderOwner isEditor=model.isEditor selectedDocuments=(mut selectedDocuments)
|
||||||
|
onDeleteSpace=(action 'onDeleteSpace') onImport=(action 'onImport')}}
|
||||||
|
{{/layout/zone-content}}
|
||||||
|
{{/layout/zone-container}}
|
|
@ -47,11 +47,6 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
setupController(controller, model) {
|
|
||||||
controller.set('model', model);
|
|
||||||
this.browser.setTitle(model.folder.get('name'));
|
|
||||||
},
|
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
error(error /*, transition*/ ) {
|
error(error /*, transition*/ ) {
|
||||||
console.log(error); // eslint-disable-line no-console
|
console.log(error); // eslint-disable-line no-console
|
||||||
|
|
20
gui/app/pods/folder/settings/controller.js
Normal file
20
gui/app/pods/folder/settings/controller.js
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// 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 Ember from 'ember';
|
||||||
|
import NotifierMixin from '../../../mixins/notifier';
|
||||||
|
import AuthProvider from '../../../mixins/auth';
|
||||||
|
|
||||||
|
export default Ember.Controller.extend(AuthProvider, NotifierMixin, {
|
||||||
|
documentService: Ember.inject.service('document'),
|
||||||
|
folderService: Ember.inject.service('folder'),
|
||||||
|
localStorage: Ember.inject.service('localStorage'),
|
||||||
|
});
|
26
gui/app/pods/folder/settings/route.js
Normal file
26
gui/app/pods/folder/settings/route.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// 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 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,
|
||||||
|
isEditor: this.modelFor('folder').isEditor,
|
||||||
|
isFolderOwner: this.modelFor('folder').isFolderOwner,
|
||||||
|
folders: this.modelFor('folder').folders
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
36
gui/app/pods/folder/settings/template.hbs
Normal file
36
gui/app/pods/folder/settings/template.hbs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
{{#layout/zone-container}}
|
||||||
|
|
||||||
|
{{#layout/zone-sidebar}}
|
||||||
|
<div class="sidebar-toolbar"></div>
|
||||||
|
<div class="sidebar-common">
|
||||||
|
{{layout/sidebar-intro title="Space Settings" message="Invite users and configure space permissions. Set up categories to sub-divide the space."}}
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-wrapper">
|
||||||
|
<div class="sidebar-menu">
|
||||||
|
<ul class="options">
|
||||||
|
<div class="option selected">Users</div>
|
||||||
|
<div class="option ">Categories</div>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/layout/zone-sidebar}}
|
||||||
|
|
||||||
|
{{#layout/zone-content}}
|
||||||
|
<div class="folder-heading">
|
||||||
|
<h1 class="folder-title">{{model.folder.name}}</h1>
|
||||||
|
</div>
|
||||||
|
{{#link-to 'folder' model.folder.id model.folder.slug class="vertical-top"}}
|
||||||
|
<i class="material-icons">arrow_back</i> back to space
|
||||||
|
{{/link-to}}
|
||||||
|
<div class="margin-top-30" />
|
||||||
|
|
||||||
|
{{#if isAuthProviderDocumize}}
|
||||||
|
{{folder/invite-user folders=model.folders folder=model.folder}}
|
||||||
|
<div class="margin-top-50" />
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{folder/permission-admin folders=model.folders folder=model.folder}}
|
||||||
|
<div class="margin-top-50" />
|
||||||
|
{{/layout/zone-content}}
|
||||||
|
|
||||||
|
{{/layout/zone-container}}
|
|
@ -1,15 +1,2 @@
|
||||||
{{layout/zone-navigation}}
|
{{layout/zone-navigation}}
|
||||||
{{#layout/zone-container}}
|
{{outlet}}
|
||||||
{{#layout/zone-sidebar}}
|
|
||||||
{{folder/sidebar-zone folders=model.folders folder=model.folder isFolderOwner=model.isFolderOwner isEditor=model.isEditor tab=tab
|
|
||||||
onAddSpace=(action 'onAddSpace')}}
|
|
||||||
{{/layout/zone-sidebar}}
|
|
||||||
{{#layout/zone-content}}
|
|
||||||
{{folder/folder-heading folder=model.folder isFolderOwner=model.isFolderOwner isEditor=model.isEditor}}
|
|
||||||
{{folder/folder-toolbar folders=model.folders folder=model.folder hasSelectedDocuments=hasSelectedDocuments
|
|
||||||
onDeleteDocument=(action 'onDeleteDocument') onMoveDocument=(action 'onMoveDocument')}}
|
|
||||||
{{folder/documents-list documents=model.documents folders=model.folders folder=model.folder templates=model.templates
|
|
||||||
isFolderOwner=model.isFolderOwner isEditor=model.isEditor selectedDocuments=(mut selectedDocuments)
|
|
||||||
onDeleteSpace=(action 'onDeleteSpace') onImport=(action 'onImport')}}
|
|
||||||
{{/layout/zone-content}}
|
|
||||||
{{/layout/zone-container}}
|
|
||||||
|
|
|
@ -23,6 +23,10 @@ export default Router.map(function () {
|
||||||
|
|
||||||
this.route('folder', {
|
this.route('folder', {
|
||||||
path: 's/:folder_id/:folder_slug'
|
path: 's/:folder_id/:folder_slug'
|
||||||
|
}, function() {
|
||||||
|
this.route('settings', {
|
||||||
|
path: 'settings'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.route('document', {
|
this.route('document', {
|
||||||
|
|
13
gui/app/serializers/user-permission.js
Normal file
13
gui/app/serializers/user-permission.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import ApplicationSerializer from './application';
|
||||||
|
|
||||||
|
export default ApplicationSerializer.extend({
|
||||||
|
normalize(modelClass, resourceHash) {
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
id: resourceHash.userId ? resourceHash.userId : 0,
|
||||||
|
type: modelClass.modelName,
|
||||||
|
attributes: resourceHash
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
|
@ -13,7 +13,6 @@ import Ember from 'ember';
|
||||||
import BaseService from '../services/base';
|
import BaseService from '../services/base';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
get,
|
|
||||||
RSVP,
|
RSVP,
|
||||||
inject: { service }
|
inject: { service }
|
||||||
} = Ember;
|
} = Ember;
|
||||||
|
@ -30,7 +29,7 @@ export default BaseService.extend({
|
||||||
|
|
||||||
// Add a new folder.
|
// Add a new folder.
|
||||||
add(payload) {
|
add(payload) {
|
||||||
return this.get('ajax').post(`folders`, {
|
return this.get('ajax').post(`space`, {
|
||||||
contentType: 'json',
|
contentType: 'json',
|
||||||
data: JSON.stringify(payload)
|
data: JSON.stringify(payload)
|
||||||
}).then((folder) => {
|
}).then((folder) => {
|
||||||
|
@ -41,7 +40,7 @@ export default BaseService.extend({
|
||||||
|
|
||||||
// Returns folder model for specified folder id.
|
// Returns folder model for specified folder id.
|
||||||
getFolder(id) {
|
getFolder(id) {
|
||||||
return this.get('ajax').request(`folders/${id}`, {
|
return this.get('ajax').request(`space/${id}`, {
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
}).then((folder) => {
|
}).then((folder) => {
|
||||||
let data = this.get('store').normalize('folder', folder);
|
let data = this.get('store').normalize('folder', folder);
|
||||||
|
@ -54,7 +53,7 @@ export default BaseService.extend({
|
||||||
|
|
||||||
// Returns all folders that user can see.
|
// Returns all folders that user can see.
|
||||||
getAll() {
|
getAll() {
|
||||||
let folders = this.get('folders');
|
let folders = this.get('space');
|
||||||
|
|
||||||
if (folders != null) {
|
if (folders != null) {
|
||||||
return new RSVP.resolve(folders);
|
return new RSVP.resolve(folders);
|
||||||
|
@ -67,7 +66,7 @@ export default BaseService.extend({
|
||||||
save(folder) {
|
save(folder) {
|
||||||
let id = folder.get('id');
|
let id = folder.get('id');
|
||||||
|
|
||||||
return this.get('ajax').request(`folders/${id}`, {
|
return this.get('ajax').request(`space/${id}`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
contentType: 'json',
|
contentType: 'json',
|
||||||
data: JSON.stringify(folder)
|
data: JSON.stringify(folder)
|
||||||
|
@ -75,7 +74,7 @@ export default BaseService.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
remove(folderId, moveToId) {
|
remove(folderId, moveToId) {
|
||||||
let url = `folders/${folderId}/move/${moveToId}`;
|
let url = `space/${folderId}/move/${moveToId}`;
|
||||||
|
|
||||||
return this.get('ajax').request(url, {
|
return this.get('ajax').request(url, {
|
||||||
method: 'DELETE'
|
method: 'DELETE'
|
||||||
|
@ -83,7 +82,7 @@ export default BaseService.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
delete(folderId) {
|
delete(folderId) {
|
||||||
return this.get('ajax').request(`folders/${folderId}`, {
|
return this.get('ajax').request(`space/${folderId}`, {
|
||||||
method: 'DELETE'
|
method: 'DELETE'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -99,7 +98,7 @@ export default BaseService.extend({
|
||||||
|
|
||||||
// getProtectedFolderInfo returns non-private folders and who has access to them.
|
// getProtectedFolderInfo returns non-private folders and who has access to them.
|
||||||
getProtectedFolderInfo() {
|
getProtectedFolderInfo() {
|
||||||
return this.get('ajax').request(`folders?filter=viewers`, {
|
return this.get('ajax').request(`space?filter=viewers`, {
|
||||||
method: "GET"
|
method: "GET"
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
let data = [];
|
let data = [];
|
||||||
|
@ -116,7 +115,7 @@ export default BaseService.extend({
|
||||||
// reloads and caches folders.
|
// reloads and caches folders.
|
||||||
reload() {
|
reload() {
|
||||||
|
|
||||||
return this.get('ajax').request(`folders`, {
|
return this.get('ajax').request(`space`, {
|
||||||
method: "GET"
|
method: "GET"
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
let data = [];
|
let data = [];
|
||||||
|
@ -132,14 +131,13 @@ export default BaseService.extend({
|
||||||
|
|
||||||
// so who can see/edit this folder?
|
// so who can see/edit this folder?
|
||||||
getPermissions(folderId) {
|
getPermissions(folderId) {
|
||||||
|
return this.get('ajax').request(`space/${folderId}/permissions`, {
|
||||||
return this.get('ajax').request(`folders/${folderId}/permissions`, {
|
|
||||||
method: "GET"
|
method: "GET"
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
let data = [];
|
let data = [];
|
||||||
|
|
||||||
data = response.map((obj) => {
|
data = response.map((obj) => {
|
||||||
let data = this.get('store').normalize('folder-permission', obj);
|
let data = this.get('store').normalize('user-permission', obj);
|
||||||
return this.get('store').push(data);
|
return this.get('store').push(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -149,7 +147,7 @@ export default BaseService.extend({
|
||||||
|
|
||||||
// persist folder permissions
|
// persist folder permissions
|
||||||
savePermissions(folderId, payload) {
|
savePermissions(folderId, payload) {
|
||||||
return this.get('ajax').request(`folders/${folderId}/permissions`, {
|
return this.get('ajax').request(`space/${folderId}/permissions`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
contentType: 'json',
|
contentType: 'json',
|
||||||
data: JSON.stringify(payload)
|
data: JSON.stringify(payload)
|
||||||
|
@ -158,7 +156,6 @@ export default BaseService.extend({
|
||||||
|
|
||||||
// share this folder with new users!
|
// share this folder with new users!
|
||||||
share(folderId, invitation) {
|
share(folderId, invitation) {
|
||||||
|
|
||||||
return this.get('ajax').post(`folders/${folderId}/invitation`, {
|
return this.get('ajax').post(`folders/${folderId}/invitation`, {
|
||||||
contentType: 'json',
|
contentType: 'json',
|
||||||
data: JSON.stringify(invitation)
|
data: JSON.stringify(invitation)
|
||||||
|
@ -171,8 +168,9 @@ export default BaseService.extend({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let folderId = folder.get('id');
|
||||||
this.set('currentFolder', folder);
|
this.set('currentFolder', folder);
|
||||||
this.get('localStorage').storeSessionItem("folder", get(folder, 'id'));
|
this.get('localStorage').storeSessionItem("folder", folderId);
|
||||||
this.set('canEditCurrentFolder', false);
|
this.set('canEditCurrentFolder', false);
|
||||||
|
|
||||||
let userId = this.get('sessionService.user.id');
|
let userId = this.get('sessionService.user.id');
|
||||||
|
@ -180,7 +178,7 @@ export default BaseService.extend({
|
||||||
userId = "0";
|
userId = "0";
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = `users/${userId}/permissions`;
|
let url = `space/${folderId}/permissions/user`;
|
||||||
|
|
||||||
return this.get('ajax').request(url).then((folderPermissions) => {
|
return this.get('ajax').request(url).then((folderPermissions) => {
|
||||||
// safety check
|
// safety check
|
||||||
|
@ -191,7 +189,6 @@ export default BaseService.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = [];
|
let result = [];
|
||||||
let folderId = folder.get('id');
|
|
||||||
|
|
||||||
folderPermissions.forEach((item) => {
|
folderPermissions.forEach((item) => {
|
||||||
if (item.folderId === folderId) {
|
if (item.folderId === folderId) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
@import "document.scss";
|
@import "document.scss";
|
||||||
@import "folder.scss";
|
@import "folder.scss";
|
||||||
@import "wizard.scss";
|
@import "wizard.scss";
|
||||||
@import "sidebar.scss";
|
@import "settings.scss";
|
||||||
|
|
42
gui/app/styles/view/folder/settings.scss
Normal file
42
gui/app/styles/view/folder/settings.scss
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
.space-settings {
|
||||||
|
> .panel {
|
||||||
|
@include content-container();
|
||||||
|
@include ease-in();
|
||||||
|
@extend .transition-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.permissions-table {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 0 30px 0;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
> .row {
|
||||||
|
padding: 8px 0;
|
||||||
|
|
||||||
|
> .permission-name-cell {
|
||||||
|
padding: 10px 5px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .permission-roles-cell {
|
||||||
|
background-color: $color-off-white;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-left: 40px;
|
||||||
|
padding: 10px 10px;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
> .role-category {
|
||||||
|
color: $color-gray;
|
||||||
|
font-weight: bold;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
> label {
|
||||||
|
color: $color-gray;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
.sidebar-folder-share {
|
|
||||||
> .input-control {
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-permissions {
|
|
||||||
> .input-control {
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .permissions-table {
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0 0 30px 0;
|
|
||||||
table-layout: fixed;
|
|
||||||
width: 100%;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
> thead {
|
|
||||||
> tr {
|
|
||||||
> th {
|
|
||||||
font-weight: bold;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
> th:nth-child(1) {
|
|
||||||
width: 70%;
|
|
||||||
}
|
|
||||||
|
|
||||||
> th:nth-child(2), td:nth-child(3) {
|
|
||||||
width: 20%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> tbody {
|
|
||||||
width: 300px;
|
|
||||||
|
|
||||||
> tr {
|
|
||||||
> td {
|
|
||||||
padding: 8px 0;
|
|
||||||
@extend .truncate;
|
|
||||||
}
|
|
||||||
|
|
||||||
> td:nth-child(1) {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
> td:nth-child(2), td:nth-child(3) {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -27,9 +27,21 @@
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
{{/dropdown-dialog}}
|
{{/dropdown-dialog}}
|
||||||
|
{{else}}
|
||||||
|
{{#if isFolderOwner}}
|
||||||
|
{{#link-to 'folder.settings' folder.id folder.slug}}{{model.document.name}}
|
||||||
|
<div class="round-button button-gray" id="space-settings-button" data-tooltip="Manage permissions" data-tooltip-position="top center">
|
||||||
|
<i class="material-icons">settings</i>
|
||||||
|
</div>
|
||||||
|
{{/link-to}}
|
||||||
|
<div class="button-gap"></div>
|
||||||
|
<div class="round-button button-gray" id="space-delete-button" data-tooltip="Delete everything" data-tooltip-position="top center">
|
||||||
|
<i class="material-icons">delete</i>
|
||||||
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="margin-top-35"></div>
|
<div class="margin-top-35"></div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
<div class="sidebar-panel">
|
<div class="space-settings">
|
||||||
<div class="title">Invite Users</div>
|
<div class="panel">
|
||||||
<div class="sidebar-folder-share folder-sidebar-form-wrapper">
|
<div class="form-header">
|
||||||
|
<div class="title">Invite</div>
|
||||||
|
<div class="tip">Share this space with co-workers</div>
|
||||||
|
</div>
|
||||||
<div class="input-control">
|
<div class="input-control">
|
||||||
<label>Email</label>
|
<label>Email</label>
|
||||||
<div class="tip">Comma separate multiple email addresses</div>
|
<div class="tip">Comma separate multiple email addresses</div>
|
||||||
|
@ -8,9 +11,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="input-control">
|
<div class="input-control">
|
||||||
<label>Message</label>
|
<label>Message</label>
|
||||||
<div class="tip">Explain why they are being invited</div>
|
<div class="tip">Explain why they are being invited to this space</div>
|
||||||
{{textarea id="explainInvite" value=inviteMessage class="input-transparent" rows="5"}}
|
{{textarea id="explainInvite" value=inviteMessage class="input-transparent" rows="5"}}
|
||||||
</div>
|
</div>
|
||||||
<div class="regular-button button-blue" {{ action 'onShare' }}>Share</div>
|
<div class="regular-button button-blue" {{ action 'onShare' }}>Invite</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
42
gui/app/templates/components/folder/permission-admin.hbs
Normal file
42
gui/app/templates/components/folder/permission-admin.hbs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<div class="space-settings">
|
||||||
|
<div class="panel">
|
||||||
|
<div class="form-header">
|
||||||
|
<div class="title">Permissions</div>
|
||||||
|
<div class="tip">Define who can do what in this space</div>
|
||||||
|
</div>
|
||||||
|
<div class="input-control">
|
||||||
|
<div class="permissions-table">
|
||||||
|
{{#each permissions key="@index" as |permission|}}
|
||||||
|
<div class="row">
|
||||||
|
<div class="permission-name-cell">{{permission.fullname}}</div>
|
||||||
|
<div class="permission-roles-cell">
|
||||||
|
<span class="role-category">Space: </span>
|
||||||
|
<input type="checkbox" id="space-role-view-{{permission.userId}}" checked={{permission.canView}} />
|
||||||
|
<label for="space-role-view-{{permission.userId}}">view</label>
|
||||||
|
<input type="checkbox" id="space-role-manage-{{permission.userId}}" checked={{permission.canView}} />
|
||||||
|
<label for="space-role-manage-{{permission.userId}}">manage</label>
|
||||||
|
<input type="checkbox" id="space-role-owner-{{permission.userId}}" checked={{permission.canView}} />
|
||||||
|
<label for="space-role-owner-{{permission.userId}}">owner</label>
|
||||||
|
|
||||||
|
<span class="role-category">Document: </span>
|
||||||
|
<input type="checkbox" id="doc-role-add-{{permission.userId}}" checked={{permission.canView}} />
|
||||||
|
<label for="doc-role-add-{{permission.userId}}">create</label>
|
||||||
|
<input type="checkbox" id="doc-role-edit-{{permission.userId}}" checked={{permission.canView}} />
|
||||||
|
<label for="doc-role-edit-{{permission.userId}}">edit</label>
|
||||||
|
<input type="checkbox" id="doc-role-delete-{{permission.userId}}" checked={{permission.canView}} />
|
||||||
|
<label for="doc-role-delete-{{permission.userId}}">delete</label>
|
||||||
|
<input type="checkbox" id="doc-role-move-{{permission.userId}}" checked={{permission.canView}} />
|
||||||
|
<label for="doc-role-move-{{permission.userId}}">move</label>
|
||||||
|
<input type="checkbox" id="doc-role-copy-{{permission.userId}}" checked={{permission.canView}} />
|
||||||
|
<label for="doc-role-copy-{{permission.userId}}">copy</label>
|
||||||
|
<input type="checkbox" id="doc-role-template-{{permission.userId}}" checked={{permission.canView}} />
|
||||||
|
<label for="doc-role-template-{{permission.userId}}">templates</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="regular-button button-blue" {{action 'setPermissions'}}>GRANT</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,30 +0,0 @@
|
||||||
<div class="sidebar-panel">
|
|
||||||
<div class="title">Space Permissions</div>
|
|
||||||
<div class="sidebar-permissions folder-sidebar-form-wrapper">
|
|
||||||
<table class="permissions-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th> </th>
|
|
||||||
<th>View </th>
|
|
||||||
<th>Edit</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{{#each permissions key="@index" as |permission|}}
|
|
||||||
<tr>
|
|
||||||
<td>{{permission.fullname}}</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" id="canView-{{permission.userId}}" checked={{permission.canView}} />
|
|
||||||
<label for="canView-{{permission.userId}}"> </label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input type="checkbox" id="canEdit-{{permission.userId}}" checked={{permission.canEdit}} />
|
|
||||||
<label for="canEdit-{{permission.userId}}"> </label>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{{/each}}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div class="regular-button button-blue" {{action 'setPermissions'}}>Set</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -11,7 +11,11 @@
|
||||||
|
|
||||||
package space
|
package space
|
||||||
|
|
||||||
import "github.com/documize/community/model"
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/documize/community/model"
|
||||||
|
)
|
||||||
|
|
||||||
// Space defines a container for documents.
|
// Space defines a container for documents.
|
||||||
type Space struct {
|
type Space struct {
|
||||||
|
@ -51,6 +55,44 @@ func (l *Space) IsRestricted() bool {
|
||||||
return l.Type == ScopeRestricted
|
return l.Type == ScopeRestricted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Permission represents a permission for a space and is persisted to the database.
|
||||||
|
type Permission struct {
|
||||||
|
ID uint64 `json:"id"`
|
||||||
|
OrgID string `json:"-"`
|
||||||
|
Who string `json:"who"` // user, role
|
||||||
|
WhoID string `json:"whoId"` // either a user or role ID
|
||||||
|
Action string `json:"action"` // view, edit, delete
|
||||||
|
Scope string `json:"scope"` // object, table
|
||||||
|
Location string `json:"location"` // table name
|
||||||
|
RefID string `json:"refId"` // id of row in table / blank when scope=table
|
||||||
|
Created time.Time `json:"created"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PermissionAction details type of action
|
||||||
|
type PermissionAction string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SpaceView action means you can view a space and documents therein
|
||||||
|
SpaceView PermissionAction = "view"
|
||||||
|
// SpaceManage action means you can add, remove users, set permissions, but not delete that space
|
||||||
|
SpaceManage PermissionAction = "manage"
|
||||||
|
// SpaceOwner action means you can delete a space and do all SpaceManage functions
|
||||||
|
SpaceOwner PermissionAction = "owner"
|
||||||
|
|
||||||
|
// DocumentAdd action means you can create/upload documents to a space
|
||||||
|
DocumentAdd PermissionAction = "doc-add"
|
||||||
|
// DocumentEdit action means you can edit documents in a space
|
||||||
|
DocumentEdit PermissionAction = "doc-edit"
|
||||||
|
// DocumentDelete means you can delete documents in a space
|
||||||
|
DocumentDelete PermissionAction = "doc-delete"
|
||||||
|
// DocumentMove means you can move documents between spaces
|
||||||
|
DocumentMove PermissionAction = "doc-move"
|
||||||
|
// DocumentCopy means you can copy documents within and between spaces
|
||||||
|
DocumentCopy PermissionAction = "doc-copy"
|
||||||
|
// DocumentTemplate means you can create, edit and delete document templates and content blocks
|
||||||
|
DocumentTemplate PermissionAction = "doc-template"
|
||||||
|
)
|
||||||
|
|
||||||
// Role determines user permissions for a folder.
|
// Role determines user permissions for a folder.
|
||||||
type Role struct {
|
type Role struct {
|
||||||
model.BaseEntityObfuscated
|
model.BaseEntityObfuscated
|
||||||
|
@ -75,7 +117,7 @@ type Viewer struct {
|
||||||
// RolesModel details which users have what permissions on a given space.
|
// RolesModel details which users have what permissions on a given space.
|
||||||
type RolesModel struct {
|
type RolesModel struct {
|
||||||
Message string
|
Message string
|
||||||
Roles []Role
|
Permissions []Permission
|
||||||
}
|
}
|
||||||
|
|
||||||
// AcceptShareModel is used to setup a user who has accepted a shared space.
|
// AcceptShareModel is used to setup a user who has accepted a shared space.
|
||||||
|
@ -100,3 +142,14 @@ type NewSpaceRequest struct {
|
||||||
CopyPermission bool `json:"copyPermission"` // copy uer permissions
|
CopyPermission bool `json:"copyPermission"` // copy uer permissions
|
||||||
CopyDocument bool `json:"copyDocument"` // copy all documents!
|
CopyDocument bool `json:"copyDocument"` // copy all documents!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasPermission checks if action matches one of the required actions?
|
||||||
|
func HasPermission(action string, actions ...PermissionAction) bool {
|
||||||
|
for _, a := range actions {
|
||||||
|
if action == string(a) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -111,19 +111,19 @@ func RegisterEndpoints(rt *env.Runtime, s *domain.Store) {
|
||||||
Add(rt, RoutePrefixPrivate, "organizations/{orgID}", []string{"GET", "OPTIONS"}, nil, organization.Get)
|
Add(rt, RoutePrefixPrivate, "organizations/{orgID}", []string{"GET", "OPTIONS"}, nil, organization.Get)
|
||||||
Add(rt, RoutePrefixPrivate, "organizations/{orgID}", []string{"PUT", "OPTIONS"}, nil, organization.Update)
|
Add(rt, RoutePrefixPrivate, "organizations/{orgID}", []string{"PUT", "OPTIONS"}, nil, organization.Update)
|
||||||
|
|
||||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}", []string{"DELETE", "OPTIONS"}, nil, space.Delete)
|
Add(rt, RoutePrefixPrivate, "space/{spaceID}", []string{"DELETE", "OPTIONS"}, nil, space.Delete)
|
||||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}/move/{moveToId}", []string{"DELETE", "OPTIONS"}, nil, space.Remove)
|
Add(rt, RoutePrefixPrivate, "space/{spaceID}/move/{moveToId}", []string{"DELETE", "OPTIONS"}, nil, space.Remove)
|
||||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}/permissions", []string{"PUT", "OPTIONS"}, nil, space.SetPermissions)
|
Add(rt, RoutePrefixPrivate, "space/{spaceID}/permissions", []string{"PUT", "OPTIONS"}, nil, space.SetPermissions)
|
||||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}/permissions", []string{"GET", "OPTIONS"}, nil, space.GetPermissions)
|
Add(rt, RoutePrefixPrivate, "space/{spaceID}/permissions/user", []string{"GET", "OPTIONS"}, nil, space.GetUserPermissions)
|
||||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}/invitation", []string{"POST", "OPTIONS"}, nil, space.Invite)
|
Add(rt, RoutePrefixPrivate, "space/{spaceID}/permissions", []string{"GET", "OPTIONS"}, nil, space.GetPermissions)
|
||||||
Add(rt, RoutePrefixPrivate, "folders", []string{"GET", "OPTIONS"}, []string{"filter", "viewers"}, space.GetSpaceViewers)
|
Add(rt, RoutePrefixPrivate, "space/{spaceID}/invitation", []string{"POST", "OPTIONS"}, nil, space.Invite)
|
||||||
Add(rt, RoutePrefixPrivate, "folders", []string{"POST", "OPTIONS"}, nil, space.Add)
|
Add(rt, RoutePrefixPrivate, "space", []string{"GET", "OPTIONS"}, []string{"filter", "viewers"}, space.GetSpaceViewers)
|
||||||
Add(rt, RoutePrefixPrivate, "folders", []string{"GET", "OPTIONS"}, nil, space.GetAll)
|
Add(rt, RoutePrefixPrivate, "space", []string{"POST", "OPTIONS"}, nil, space.Add)
|
||||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}", []string{"GET", "OPTIONS"}, nil, space.Get)
|
Add(rt, RoutePrefixPrivate, "space", []string{"GET", "OPTIONS"}, nil, space.GetAll)
|
||||||
Add(rt, RoutePrefixPrivate, "folders/{folderID}", []string{"PUT", "OPTIONS"}, nil, space.Update)
|
Add(rt, RoutePrefixPrivate, "space/{spaceID}", []string{"GET", "OPTIONS"}, nil, space.Get)
|
||||||
|
Add(rt, RoutePrefixPrivate, "space/{spaceID}", []string{"PUT", "OPTIONS"}, nil, space.Update)
|
||||||
|
|
||||||
Add(rt, RoutePrefixPrivate, "users/{userID}/password", []string{"POST", "OPTIONS"}, nil, user.ChangePassword)
|
Add(rt, RoutePrefixPrivate, "users/{userID}/password", []string{"POST", "OPTIONS"}, nil, user.ChangePassword)
|
||||||
Add(rt, RoutePrefixPrivate, "users/{userID}/permissions", []string{"GET", "OPTIONS"}, nil, user.UserSpacePermissions)
|
|
||||||
Add(rt, RoutePrefixPrivate, "users", []string{"POST", "OPTIONS"}, nil, user.Add)
|
Add(rt, RoutePrefixPrivate, "users", []string{"POST", "OPTIONS"}, nil, user.Add)
|
||||||
Add(rt, RoutePrefixPrivate, "users/folder/{folderID}", []string{"GET", "OPTIONS"}, nil, user.GetSpaceUsers)
|
Add(rt, RoutePrefixPrivate, "users/folder/{folderID}", []string{"GET", "OPTIONS"}, nil, user.GetSpaceUsers)
|
||||||
Add(rt, RoutePrefixPrivate, "users", []string{"GET", "OPTIONS"}, nil, user.GetOrganizationUsers)
|
Add(rt, RoutePrefixPrivate, "users", []string{"GET", "OPTIONS"}, nil, user.GetOrganizationUsers)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue