mirror of
https://github.com/documize/community.git
synced 2025-08-08 06:55:28 +02:00
major code repair from old to new API -- WIP
This commit is contained in:
parent
25b576f861
commit
792c3e2ce8
46 changed files with 3403 additions and 171 deletions
|
@ -12,3 +12,757 @@
|
|||
// Package space handles API calls and persistence for spaces.
|
||||
// Spaces in Documize contain documents.
|
||||
package space
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/documize/api/wordsmith/log"
|
||||
"github.com/documize/community/core/api/mail"
|
||||
"github.com/documize/community/core/request"
|
||||
"github.com/documize/community/core/response"
|
||||
"github.com/documize/community/core/secrets"
|
||||
"github.com/documize/community/core/streamutil"
|
||||
"github.com/documize/community/core/stringutil"
|
||||
"github.com/documize/community/core/uniqueid"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/account"
|
||||
"github.com/documize/community/domain/document"
|
||||
"github.com/documize/community/domain/eventing"
|
||||
"github.com/documize/community/domain/organization"
|
||||
"github.com/documize/community/domain/pin"
|
||||
"github.com/documize/community/domain/user"
|
||||
)
|
||||
|
||||
// Add creates a new space.
|
||||
func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
|
||||
method := "AddSpace"
|
||||
ctx, s := domain.NewContexts(h.Runtime, r)
|
||||
|
||||
if !h.Runtime.Product.License.IsValid() {
|
||||
response.WriteBadLicense(w)
|
||||
return
|
||||
}
|
||||
|
||||
if !ctx.Editor {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
defer streamutil.Close(r.Body)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var space = Space{}
|
||||
err = json.Unmarshal(body, &space)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(space.Name) == 0 {
|
||||
response.WriteMissingDataError(w, method, "name")
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
space.RefID = uniqueid.Generate()
|
||||
space.OrgID = ctx.OrgID
|
||||
|
||||
err = addSpace(s, space)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeSpaceAdd)
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
space, _ = Get(s, space.RefID)
|
||||
|
||||
response.WriteJSON(w, space)
|
||||
}
|
||||
|
||||
// Get returns the requested space.
|
||||
func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
method := "Get"
|
||||
_, s := domain.NewContexts(h.Runtime, r)
|
||||
|
||||
id := request.Param(r, "folderID")
|
||||
if len(id) == 0 {
|
||||
response.WriteMissingDataError(w, method, "folderID")
|
||||
return
|
||||
}
|
||||
|
||||
sp, err := Get(s, id)
|
||||
if err == sql.ErrNoRows {
|
||||
response.WriteNotFoundError(w, method, id)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteJSON(w, sp)
|
||||
}
|
||||
|
||||
// GetAll returns spaces the user can see.
|
||||
func (h *Handler) GetAll(w http.ResponseWriter, r *http.Request) {
|
||||
method := "GetAll"
|
||||
_, s := domain.NewContexts(h.Runtime, r)
|
||||
|
||||
sp, err := GetAll(s)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(sp) == 0 {
|
||||
sp = []Space{}
|
||||
}
|
||||
|
||||
response.WriteJSON(w, sp)
|
||||
}
|
||||
|
||||
// GetSpaceViewers returns the users that can see the shared spaces.
|
||||
func (h *Handler) GetSpaceViewers(w http.ResponseWriter, r *http.Request) {
|
||||
method := "GetSpaceViewers"
|
||||
_, s := domain.NewContexts(h.Runtime, r)
|
||||
|
||||
v, err := Viewers(s)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(v) == 0 {
|
||||
v = []Viewer{}
|
||||
}
|
||||
|
||||
response.WriteJSON(w, v)
|
||||
}
|
||||
|
||||
// Update processes request to save space object to the database
|
||||
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.Update"
|
||||
ctx, s := domain.NewContexts(h.Runtime, r)
|
||||
|
||||
if !ctx.Editor {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
folderID := request.Param(r, "folderID")
|
||||
if len(folderID) == 0 {
|
||||
response.WriteMissingDataError(w, method, "folderID")
|
||||
return
|
||||
}
|
||||
|
||||
defer streamutil.Close(r.Body)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var sp Space
|
||||
err = json.Unmarshal(body, &sp)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, "marshal")
|
||||
return
|
||||
}
|
||||
|
||||
if len(sp.Name) == 0 {
|
||||
response.WriteMissingDataError(w, method, "name")
|
||||
return
|
||||
}
|
||||
|
||||
sp.RefID = folderID
|
||||
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = Update(s, sp)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeSpaceUpdate)
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
response.WriteJSON(w, sp)
|
||||
}
|
||||
|
||||
// Remove moves documents to another folder before deleting it
|
||||
func (h *Handler) Remove(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.Remove"
|
||||
ctx, s := domain.NewContexts(h.Runtime, r)
|
||||
|
||||
if !h.Runtime.Product.License.IsValid() {
|
||||
response.WriteBadLicense(w)
|
||||
return
|
||||
}
|
||||
|
||||
if !ctx.Editor {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
id := request.Param(r, "folderID")
|
||||
move := request.Param(r, "moveToId")
|
||||
|
||||
if len(id) == 0 {
|
||||
response.WriteMissingDataError(w, method, "folderID")
|
||||
return
|
||||
}
|
||||
if len(move) == 0 {
|
||||
response.WriteMissingDataError(w, method, "moveToId")
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = Delete(s, id)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = document.MoveDocumentSpace(s, id, move)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = MoveSpaceRoles(s, id, move)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = pin.DeletePinnedSpace(s, id)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeSpaceDelete)
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
||||
// Delete deletes empty space.
|
||||
func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.Delete"
|
||||
ctx, s := domain.NewContexts(h.Runtime, r)
|
||||
|
||||
if !h.Runtime.Product.License.IsValid() {
|
||||
response.WriteBadLicense(w)
|
||||
return
|
||||
}
|
||||
|
||||
if !ctx.Editor {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
id := request.Param(r, "folderID")
|
||||
if len(id) == 0 {
|
||||
response.WriteMissingDataError(w, method, "folderID")
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = Delete(s, id)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = DeleteSpaceRoles(s, id)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = pin.DeletePinnedSpace(s, id)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeSpaceDelete)
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
||||
// SetPermissions persists specified spac3 permissions
|
||||
func (h *Handler) SetPermissions(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.SetPermissions"
|
||||
ctx, s := domain.NewContexts(h.Runtime, r)
|
||||
|
||||
if !ctx.Editor {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
id := request.Param(r, "folderID")
|
||||
if len(id) == 0 {
|
||||
response.WriteMissingDataError(w, method, "folderID")
|
||||
return
|
||||
}
|
||||
|
||||
sp, err := Get(s, id)
|
||||
if err != nil {
|
||||
response.WriteNotFoundError(w, method, "No such space")
|
||||
return
|
||||
}
|
||||
|
||||
if sp.UserID != s.Context.UserID {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
defer streamutil.Close(r.Body)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var model = RolesModel{}
|
||||
err = json.Unmarshal(body, &model)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// We compare new permisions to what we had before.
|
||||
// Why? So we can send out folder invitation emails.
|
||||
previousRoles, err := GetRoles(s, id)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Store all previous roles as map for easy querying
|
||||
previousRoleUsers := make(map[string]bool)
|
||||
|
||||
for _, v := range previousRoles {
|
||||
previousRoleUsers[v.UserID] = true
|
||||
}
|
||||
|
||||
// Who is sharing this folder?
|
||||
inviter, err := user.Get(s, s.Context.UserID)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Nuke all previous permissions for this folder
|
||||
_, err = DeleteSpaceRoles(s, id)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
me := false
|
||||
hasEveryoneRole := false
|
||||
roleCount := 0
|
||||
|
||||
url := s.Context.GetAppURL(fmt.Sprintf("s/%s/%s", sp.RefID, stringutil.MakeSlug(sp.Name)))
|
||||
|
||||
for _, role := range model.Roles {
|
||||
role.OrgID = s.Context.OrgID
|
||||
role.LabelID = id
|
||||
|
||||
// Ensure the folder owner always has access!
|
||||
if role.UserID == s.Context.UserID {
|
||||
me = true
|
||||
role.CanView = true
|
||||
role.CanEdit = true
|
||||
}
|
||||
|
||||
if len(role.UserID) == 0 && (role.CanView || role.CanEdit) {
|
||||
hasEveryoneRole = true
|
||||
}
|
||||
|
||||
// Only persist if there is a role!
|
||||
if role.CanView || role.CanEdit {
|
||||
roleID := uniqueid.Generate()
|
||||
role.RefID = roleID
|
||||
err = AddRole(s, role)
|
||||
roleCount++
|
||||
log.IfErr(err)
|
||||
|
||||
// We send out folder invitation emails to those users
|
||||
// that have *just* been given permissions.
|
||||
if _, isExisting := previousRoleUsers[role.UserID]; !isExisting {
|
||||
|
||||
// we skip 'everyone' (user id != empty string)
|
||||
if len(role.UserID) > 0 {
|
||||
var existingUser user.User
|
||||
existingUser, err = user.Get(s, role.UserID)
|
||||
|
||||
if err == nil {
|
||||
go mail.ShareFolderExistingUser(existingUser.Email, inviter.Fullname(), url, sp.Name, model.Message)
|
||||
h.Runtime.Log.Info(fmt.Sprintf("%s is sharing space %s with existing user %s", inviter.Email, sp.Name, existingUser.Email))
|
||||
} else {
|
||||
response.WriteServerError(w, method, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do we need to ensure permissions for space owner when shared?
|
||||
if !me {
|
||||
role := Role{}
|
||||
role.LabelID = id
|
||||
role.OrgID = s.Context.OrgID
|
||||
role.UserID = s.Context.UserID
|
||||
role.CanEdit = true
|
||||
role.CanView = true
|
||||
roleID := uniqueid.Generate()
|
||||
role.RefID = roleID
|
||||
|
||||
err = AddRole(s, role)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Mark up folder type as either public, private or restricted access.
|
||||
if hasEveryoneRole {
|
||||
sp.Type = ScopePublic
|
||||
} else {
|
||||
if roleCount > 1 {
|
||||
sp.Type = ScopeRestricted
|
||||
} else {
|
||||
sp.Type = ScopePrivate
|
||||
}
|
||||
}
|
||||
|
||||
err = Update(s, sp)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeSpacePermission)
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
||||
// GetPermissions returns user permissions for the requested folder.
|
||||
func (h *Handler) GetPermissions(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.GetPermissions"
|
||||
_, s := domain.NewContexts(h.Runtime, r)
|
||||
|
||||
folderID := request.Param(r, "folderID")
|
||||
if len(folderID) == 0 {
|
||||
response.WriteMissingDataError(w, method, "folderID")
|
||||
return
|
||||
}
|
||||
|
||||
roles, err := GetRoles(s, folderID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(roles) == 0 {
|
||||
roles = []Role{}
|
||||
}
|
||||
|
||||
response.WriteJSON(w, roles)
|
||||
}
|
||||
|
||||
// AcceptInvitation records the fact that a user has completed space onboard process.
|
||||
func (h *Handler) AcceptInvitation(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.AcceptInvitation"
|
||||
ctx, s := domain.NewContexts(h.Runtime, r)
|
||||
|
||||
folderID := request.Param(r, "folderID")
|
||||
if len(folderID) == 0 {
|
||||
response.WriteMissingDataError(w, method, "folderID")
|
||||
return
|
||||
}
|
||||
|
||||
org, err := organization.GetOrganizationByDomain(s, ctx.Subdomain)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// AcceptShare does not authenticate the user hence the context needs to set up
|
||||
ctx.OrgID = org.RefID
|
||||
s.Context.OrgID = org.RefID
|
||||
|
||||
defer streamutil.Close(r.Body)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var model = AcceptShareModel{}
|
||||
err = json.Unmarshal(body, &model)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(model.Serial) == 0 || len(model.Firstname) == 0 || len(model.Lastname) == 0 || len(model.Password) == 0 {
|
||||
response.WriteMissingDataError(w, method, "Serial, Firstname, Lastname, Password")
|
||||
return
|
||||
}
|
||||
|
||||
u, err := user.GetBySerial(s, model.Serial)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
response.WriteDuplicateError(w, method, "user")
|
||||
return
|
||||
}
|
||||
|
||||
// AcceptShare does not authenticate the user hence the context needs to set up
|
||||
ctx.UserID = u.RefID
|
||||
s.Context.UserID = u.RefID
|
||||
|
||||
u.Firstname = model.Firstname
|
||||
u.Lastname = model.Lastname
|
||||
u.Initials = stringutil.MakeInitials(u.Firstname, u.Lastname)
|
||||
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = user.UpdateUser(s, u)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
salt := secrets.GenerateSalt()
|
||||
|
||||
err = user.UpdateUserPassword(s, u.RefID, salt, secrets.GeneratePassword(model.Password, salt))
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeSpaceJoin)
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
response.WriteJSON(w, u)
|
||||
}
|
||||
|
||||
// Invite sends users folder invitation emails.
|
||||
func (h *Handler) Invite(w http.ResponseWriter, r *http.Request) {
|
||||
method := "space.Invite"
|
||||
ctx, s := domain.NewContexts(h.Runtime, r)
|
||||
|
||||
id := request.Param(r, "folderID")
|
||||
if len(id) == 0 {
|
||||
response.WriteMissingDataError(w, method, "folderID")
|
||||
return
|
||||
}
|
||||
|
||||
sp, err := Get(s, id)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if sp.UserID != s.Context.UserID {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
|
||||
defer streamutil.Close(r.Body)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, "body")
|
||||
return
|
||||
}
|
||||
|
||||
var model = InvitationModel{}
|
||||
err = json.Unmarshal(body, &model)
|
||||
if err != nil {
|
||||
response.WriteBadRequestError(w, method, "json")
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Transaction, err = h.Runtime.Db.Beginx()
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
inviter, err := user.Get(s, ctx.UserID)
|
||||
if err != nil {
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, email := range model.Recipients {
|
||||
u, err := user.GetByEmail(s, email)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(u.RefID) > 0 {
|
||||
// Ensure they have access to this organization
|
||||
accounts, err2 := account.GetUserAccounts(s, u.RefID)
|
||||
if err2 != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
// we create if they c
|
||||
hasAccess := false
|
||||
for _, a := range accounts {
|
||||
if a.OrgID == s.Context.OrgID {
|
||||
hasAccess = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hasAccess {
|
||||
var a account.Account
|
||||
a.UserID = u.RefID
|
||||
a.OrgID = s.Context.OrgID
|
||||
a.Admin = false
|
||||
a.Editor = false
|
||||
a.Active = true
|
||||
accountID := uniqueid.Generate()
|
||||
a.RefID = accountID
|
||||
|
||||
err = account.Add(s, a)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure they have space roles
|
||||
DeleteUserSpaceRoles(s, sp.RefID, u.RefID)
|
||||
|
||||
role := Role{}
|
||||
role.LabelID = sp.RefID
|
||||
role.OrgID = ctx.OrgID
|
||||
role.UserID = u.RefID
|
||||
role.CanEdit = false
|
||||
role.CanView = true
|
||||
roleID := uniqueid.Generate()
|
||||
role.RefID = roleID
|
||||
|
||||
err = AddRole(s, role)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
url := ctx.GetAppURL(fmt.Sprintf("s/%s/%s", sp.RefID, stringutil.MakeSlug(sp.Name)))
|
||||
go mail.ShareFolderExistingUser(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))
|
||||
} else {
|
||||
// On-board new user
|
||||
if strings.Contains(email, "@") {
|
||||
url := ctx.GetAppURL(fmt.Sprintf("auth/share/%s/%s", sp.RefID, stringutil.MakeSlug(sp.Name)))
|
||||
err = inviteNewUserToSharedSpace(s, email, inviter, url, sp, model.Message)
|
||||
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
|
||||
h.Runtime.Log.Info(fmt.Sprintf("%s is sharing space %s with new user %s", inviter.Email, sp.Name, email))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We ensure that the folder is marked as restricted as a minimum!
|
||||
if len(model.Recipients) > 0 && sp.Type == ScopePrivate {
|
||||
sp.Type = ScopeRestricted
|
||||
|
||||
err = Update(s, sp)
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
response.WriteServerError(w, method, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
eventing.Record(s, eventing.EventTypeSpaceInvite)
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
response.WriteEmpty(w)
|
||||
}
|
||||
|
|
|
@ -12,3 +12,92 @@
|
|||
// Package space handles API calls and persistence for spaces.
|
||||
// Spaces in Documize contain documents.
|
||||
package space
|
||||
|
||||
import (
|
||||
"github.com/documize/community/core/env"
|
||||
"github.com/documize/community/domain"
|
||||
)
|
||||
|
||||
// Handler contains the runtime information such as logging and database.
|
||||
type Handler struct {
|
||||
Runtime env.Runtime
|
||||
}
|
||||
|
||||
// Space defines a container for documents.
|
||||
type Space struct {
|
||||
domain.BaseEntity
|
||||
Name string `json:"name"`
|
||||
OrgID string `json:"orgId"`
|
||||
UserID string `json:"userId"`
|
||||
Type Scope `json:"folderType"`
|
||||
}
|
||||
|
||||
// Scope determines folder visibility.
|
||||
type Scope int
|
||||
|
||||
const (
|
||||
// ScopePublic can be seen by anyone
|
||||
ScopePublic Scope = 1
|
||||
|
||||
// ScopePrivate can only be seen by the person who owns it
|
||||
ScopePrivate Scope = 2
|
||||
|
||||
// ScopeRestricted can be seen by selected users
|
||||
ScopeRestricted Scope = 3
|
||||
)
|
||||
|
||||
// IsPublic means the folder can be seen by anyone.
|
||||
func (l *Space) IsPublic() bool {
|
||||
return l.Type == ScopePublic
|
||||
}
|
||||
|
||||
// IsPrivate means the folder can only be seen by the person who owns it.
|
||||
func (l *Space) IsPrivate() bool {
|
||||
return l.Type == ScopePrivate
|
||||
}
|
||||
|
||||
// IsRestricted means the folder can be seen by selected users.
|
||||
func (l *Space) IsRestricted() bool {
|
||||
return l.Type == ScopeRestricted
|
||||
}
|
||||
|
||||
// Role determines user permissions for a folder.
|
||||
type Role struct {
|
||||
domain.BaseEntityObfuscated
|
||||
OrgID string `json:"-"`
|
||||
LabelID string `json:"folderId"`
|
||||
UserID string `json:"userId"`
|
||||
CanView bool `json:"canView"`
|
||||
CanEdit bool `json:"canEdit"`
|
||||
}
|
||||
|
||||
// Viewer details who can see a particular space
|
||||
type Viewer struct {
|
||||
Name string `json:"name"`
|
||||
LabelID string `json:"folderId"`
|
||||
Type int `json:"folderType"`
|
||||
UserID string `json:"userId"`
|
||||
Firstname string `json:"firstname"`
|
||||
Lastname string `json:"lastname"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
// RolesModel details which users have what permissions on a given space.
|
||||
type RolesModel struct {
|
||||
Message string
|
||||
Roles []Role
|
||||
}
|
||||
|
||||
// AcceptShareModel is used to setup a user who has accepted a shared space.
|
||||
type AcceptShareModel struct {
|
||||
Serial string `json:"serial"`
|
||||
Firstname string `json:"firstname"`
|
||||
Lastname string `json:"lastname"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// InvitationModel details which users have been invited to a space.
|
||||
type InvitationModel struct {
|
||||
Message string
|
||||
Recipients []string
|
||||
}
|
||||
|
|
|
@ -12,3 +12,51 @@
|
|||
// Package space handles API calls and persistence for spaces.
|
||||
// Spaces in Documize contain documents.
|
||||
package space
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/documize/community/domain"
|
||||
)
|
||||
|
||||
// CanViewSpace returns if the user has permission to view the given spaceID.
|
||||
func CanViewSpace(s domain.StoreContext, spaceID string) (hasPermission bool) {
|
||||
roles, err := GetRoles(s, spaceID)
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
s.Runtime.Log.Error(fmt.Sprintf("check space permissions %s", spaceID), err)
|
||||
return false
|
||||
}
|
||||
|
||||
for _, role := range roles {
|
||||
if role.LabelID == spaceID && (role.CanView || role.CanEdit) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// CanViewSpaceDocuments returns if the user has permission to view a document within the specified space.
|
||||
func CanViewSpaceDocuments(s domain.StoreContext, spaceID string) (hasPermission bool) {
|
||||
roles, err := GetRoles(s, spaceID)
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
s.Runtime.Log.Error(fmt.Sprintf("check space permissions %s", spaceID), err)
|
||||
return false
|
||||
}
|
||||
|
||||
for _, role := range roles {
|
||||
if role.LabelID == spaceID && (role.CanView || role.CanEdit) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
103
domain/space/space.go
Normal file
103
domain/space/space.go
Normal file
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// This software (Documize Community Edition) is licensed under
|
||||
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
//
|
||||
// You can operate outside the AGPL restrictions by purchasing
|
||||
// Documize Enterprise Edition and obtaining a commercial license
|
||||
// by contacting <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
package space
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/documize/community/core/api/mail"
|
||||
"github.com/documize/community/core/secrets"
|
||||
"github.com/documize/community/core/uniqueid"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/account"
|
||||
"github.com/documize/community/domain/user"
|
||||
)
|
||||
|
||||
// addSpace prepares and creates space record.
|
||||
func addSpace(s domain.StoreContext, sp Space) (err error) {
|
||||
sp.Type = ScopePrivate
|
||||
sp.UserID = s.Context.UserID
|
||||
|
||||
err = Add(s, sp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
role := Role{}
|
||||
role.LabelID = sp.RefID
|
||||
role.OrgID = sp.OrgID
|
||||
role.UserID = s.Context.UserID
|
||||
role.CanEdit = true
|
||||
role.CanView = true
|
||||
role.RefID = uniqueid.Generate()
|
||||
|
||||
err = AddRole(s, 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
|
||||
// through a welcome process designed to capture profile data.
|
||||
// We add them to the organization and grant them view-only folder access.
|
||||
func inviteNewUserToSharedSpace(s domain.StoreContext, email string, invitedBy user.User,
|
||||
baseURL string, sp Space, invitationMessage string) (err error) {
|
||||
|
||||
var u = user.User{}
|
||||
u.Email = email
|
||||
u.Firstname = email
|
||||
u.Lastname = ""
|
||||
u.Salt = secrets.GenerateSalt()
|
||||
requestedPassword := secrets.GenerateRandomPassword()
|
||||
u.Password = secrets.GeneratePassword(requestedPassword, u.Salt)
|
||||
userID := uniqueid.Generate()
|
||||
u.RefID = userID
|
||||
|
||||
err = user.Add(s, u)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Let's give this user access to the organization
|
||||
var a account.Account
|
||||
a.UserID = userID
|
||||
a.OrgID = s.Context.OrgID
|
||||
a.Admin = false
|
||||
a.Editor = false
|
||||
a.Active = true
|
||||
accountID := uniqueid.Generate()
|
||||
a.RefID = accountID
|
||||
|
||||
err = account.Add(s, a)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
role := Role{}
|
||||
role.LabelID = sp.RefID
|
||||
role.OrgID = s.Context.OrgID
|
||||
role.UserID = userID
|
||||
role.CanEdit = false
|
||||
role.CanView = true
|
||||
roleID := uniqueid.Generate()
|
||||
role.RefID = roleID
|
||||
|
||||
err = AddRole(s, role)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/%s", baseURL, u.Salt)
|
||||
go mail.ShareFolderNewUser(u.Email, invitedBy.Fullname(), url, sp.Name, invitationMessage)
|
||||
|
||||
return
|
||||
}
|
286
domain/space/store.go
Normal file
286
domain/space/store.go
Normal file
|
@ -0,0 +1,286 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// This software (Documize Community Edition) is licensed under
|
||||
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
//
|
||||
// You can operate outside the AGPL restrictions by purchasing
|
||||
// Documize Enterprise Edition and obtaining a commercial license
|
||||
// by contacting <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
// Package space handles API calls and persistence for spaces.
|
||||
// Spaces in Documize contain documents.
|
||||
package space
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/documize/community/core/streamutil"
|
||||
"github.com/documize/community/domain"
|
||||
"github.com/documize/community/domain/store/mysql"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Add adds new folder into the store.
|
||||
func Add(s domain.StoreContext, sp Space) (err error) {
|
||||
sp.UserID = s.Context.UserID
|
||||
sp.Created = time.Now().UTC()
|
||||
sp.Revised = time.Now().UTC()
|
||||
|
||||
stmt, err := s.Context.Transaction.Preparex("INSERT INTO label (refid, label, orgid, userid, type, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?)")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "unable to prepare insert for label")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = stmt.Exec(sp.RefID, sp.Name, sp.OrgID, sp.UserID, sp.Type, sp.Created, sp.Revised)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "unable to execute insert for label")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns a space from the store.
|
||||
func Get(s domain.StoreContext, id string) (sp Space, err error) {
|
||||
stmt, err := s.Runtime.Db.Preparex("SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label WHERE orgid=? and refid=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to prepare select for label %s", id))
|
||||
return
|
||||
}
|
||||
|
||||
err = stmt.Get(&sp, s.Context.OrgID, id)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute select for label %s", id))
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// PublicSpaces returns folders that anyone can see.
|
||||
func PublicSpaces(s domain.StoreContext, orgID string) (sp []Space, err error) {
|
||||
sql := "SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label a where orgid=? AND type=1"
|
||||
|
||||
err = s.Runtime.Db.Select(&sp, sql, orgID)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("Unable to execute GetPublicFolders for org %s", orgID))
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GetAll returns folders that the user can see.
|
||||
// Also handles which folders can be seen by anonymous users.
|
||||
func GetAll(s domain.StoreContext) (sp []Space, err error) {
|
||||
sql := `
|
||||
(SELECT id,refid,label as name,orgid,userid,type,created,revised from label WHERE orgid=? AND type=2 AND userid=?)
|
||||
UNION ALL
|
||||
(SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label a where orgid=? AND type=1 AND refid in
|
||||
(SELECT labelid from labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1)))
|
||||
UNION ALL
|
||||
(SELECT id,refid,label as name,orgid,userid,type,created,revised FROM label a where orgid=? AND type=3 AND refid in
|
||||
(SELECT labelid from labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1)))
|
||||
ORDER BY name`
|
||||
|
||||
err = s.Runtime.Db.Select(&sp, sql,
|
||||
s.Context.OrgID,
|
||||
s.Context.UserID,
|
||||
s.Context.OrgID,
|
||||
s.Context.OrgID,
|
||||
s.Context.OrgID,
|
||||
s.Context.OrgID,
|
||||
s.Context.UserID)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("Unable to execute select labels for org %s", s.Context.OrgID))
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Update saves space changes.
|
||||
func Update(s domain.StoreContext, sp Space) (err error) {
|
||||
sp.Revised = time.Now().UTC()
|
||||
|
||||
stmt, err := s.Context.Transaction.PrepareNamed("UPDATE label SET label=:name, type=:type, userid=:userid, revised=:revised WHERE orgid=:orgid AND refid=:refid")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to prepare update for label %s", sp.RefID))
|
||||
return
|
||||
}
|
||||
|
||||
_, err = stmt.Exec(&sp)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute update for label %s", sp.RefID))
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ChangeOwner transfer space ownership.
|
||||
func ChangeOwner(s domain.StoreContext, currentOwner, newOwner string) (err error) {
|
||||
stmt, err := s.Context.Transaction.Preparex("UPDATE label SET userid=? WHERE userid=? AND orgid=?")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to prepare change space owner for %s", currentOwner))
|
||||
return
|
||||
}
|
||||
|
||||
_, err = stmt.Exec(newOwner, currentOwner, s.Context.OrgID)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute change space owner for %s", currentOwner))
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Viewers returns the list of people who can see shared folders.
|
||||
func Viewers(s domain.StoreContext) (v []Viewer, err error) {
|
||||
sql := `
|
||||
SELECT a.userid,
|
||||
COALESCE(u.firstname, '') as firstname,
|
||||
COALESCE(u.lastname, '') as lastname,
|
||||
COALESCE(u.email, '') as email,
|
||||
a.labelid,
|
||||
b.label as name,
|
||||
b.type
|
||||
FROM labelrole a
|
||||
LEFT JOIN label b ON b.refid=a.labelid
|
||||
LEFT JOIN user u ON u.refid=a.userid
|
||||
WHERE a.orgid=? AND b.type != 2
|
||||
GROUP BY a.labelid,a.userid
|
||||
ORDER BY u.firstname,u.lastname`
|
||||
|
||||
err = s.Runtime.Db.Select(&v, sql, s.Context.OrgID)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Delete removes space from the store.
|
||||
func Delete(s domain.StoreContext, id string) (rows int64, err error) {
|
||||
b := mysql.BaseQuery{}
|
||||
return b.DeleteConstrained(s.Context.Transaction, "label", s.Context.OrgID, id)
|
||||
}
|
||||
|
||||
// AddRole inserts the given record into the labelrole database table.
|
||||
func AddRole(s domain.StoreContext, r Role) (err error) {
|
||||
r.Created = time.Now().UTC()
|
||||
r.Revised = time.Now().UTC()
|
||||
|
||||
stmt, err := s.Context.Transaction.Preparex("INSERT INTO labelrole (refid, labelid, orgid, userid, canview, canedit, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?)")
|
||||
defer streamutil.Close(stmt)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "unable to prepare insert for space role")
|
||||
return
|
||||
}
|
||||
|
||||
_, err = stmt.Exec(r.RefID, r.LabelID, r.OrgID, r.UserID, r.CanView, r.CanEdit, r.Created, r.Revised)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "unable to execute insert for space role")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GetRoles returns a slice of labelrole records, for the given labelID in the client's organization, grouped by user.
|
||||
func GetRoles(s domain.StoreContext, labelID string) (r []Role, err error) {
|
||||
query := `SELECT id, refid, labelid, orgid, userid, canview, canedit, created, revised FROM labelrole WHERE orgid=? AND labelid=?` // was + "GROUP BY userid"
|
||||
|
||||
err = s.Runtime.Db.Select(&r, query, s.Context.OrgID, labelID)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// GetUserRoles returns a slice of role records, for both the client's user and organization, and
|
||||
// those space roles that exist for all users in the client's organization.
|
||||
func GetUserRoles(s domain.StoreContext) (r []Role, err error) {
|
||||
err = s.Runtime.Db.Select(&r, `
|
||||
SELECT id, refid, labelid, orgid, userid, canview, canedit, created, revised FROM labelrole WHERE orgid=? and userid=?
|
||||
UNION ALL
|
||||
SELECT id, refid, labelid, orgid, userid, canview, canedit, created, revised FROM labelrole WHERE orgid=? AND userid=''`,
|
||||
s.Context.OrgID, s.Context.UserID, s.Context.OrgID)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute select for user space roles %s", s.Context.UserID))
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteRole deletes the labelRoleID record from the labelrole table.
|
||||
func DeleteRole(s domain.StoreContext, roleID string) (rows int64, err error) {
|
||||
b := mysql.BaseQuery{}
|
||||
|
||||
sql := fmt.Sprintf("DELETE FROM labelrole WHERE orgid='%s' AND refid='%s'", s.Context.OrgID, roleID)
|
||||
|
||||
return b.DeleteWhere(s.Context.Transaction, sql)
|
||||
}
|
||||
|
||||
// DeleteSpaceRoles deletes records from the labelrole table which have the given space ID.
|
||||
func DeleteSpaceRoles(s domain.StoreContext, spaceID string) (rows int64, err error) {
|
||||
b := mysql.BaseQuery{}
|
||||
|
||||
sql := fmt.Sprintf("DELETE FROM labelrole WHERE orgid='%s' AND labelid='%s'", s.Context.OrgID, spaceID)
|
||||
|
||||
return b.DeleteWhere(s.Context.Transaction, sql)
|
||||
}
|
||||
|
||||
// DeleteUserSpaceRoles removes all roles for the specified user, for the specified space.
|
||||
func DeleteUserSpaceRoles(s domain.StoreContext, 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'",
|
||||
s.Context.OrgID, spaceID, userID)
|
||||
|
||||
return b.DeleteWhere(s.Context.Transaction, sql)
|
||||
}
|
||||
|
||||
// MoveSpaceRoles changes the space ID for space role records from previousLabel to newLabel.
|
||||
func MoveSpaceRoles(s domain.StoreContext, previousLabel, newLabel string) (err error) {
|
||||
stmt, err := s.Context.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, s.Context.OrgID)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("unable to execute move space roles for label %s", previousLabel))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// This software (Documize Community Edition) is licensed under
|
||||
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
//
|
||||
// You can operate outside the AGPL restrictions by purchasing
|
||||
// Documize Enterprise Edition and obtaining a commercial license
|
||||
// by contacting <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
// Package space handles API calls and persistence for spaces.
|
||||
// Spaces in Documize contain documents.
|
||||
package space
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
|
||||
//
|
||||
// This software (Documize Community Edition) is licensed under
|
||||
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
//
|
||||
// You can operate outside the AGPL restrictions by purchasing
|
||||
// Documize Enterprise Edition and obtaining a commercial license
|
||||
// by contacting <sales@documize.com>.
|
||||
//
|
||||
// https://documize.com
|
||||
|
||||
// Package space handles API calls and persistence for spaces.
|
||||
// Spaces in Documize contain documents.
|
||||
package space
|
Loading…
Add table
Add a link
Reference in a new issue