2017-07-24 16:24:21 +01:00
// 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
2017-07-26 10:50:26 +01:00
// Package mysql handles data persistence for spaces.
package mysql
2017-07-24 16:24:21 +01:00
import (
"database/sql"
"fmt"
"time"
2017-07-26 10:50:26 +01:00
"github.com/documize/community/core/env"
2017-07-24 16:24:21 +01:00
"github.com/documize/community/core/streamutil"
"github.com/documize/community/domain"
"github.com/documize/community/domain/store/mysql"
2017-07-26 10:50:26 +01:00
"github.com/documize/community/model/space"
2017-07-24 16:24:21 +01:00
"github.com/pkg/errors"
)
2017-07-26 10:50:26 +01:00
// Scope provides data access to MySQL.
type Scope struct {
Runtime * env . Runtime
}
2017-07-24 16:24:21 +01:00
// Add adds new folder into the store.
2017-07-26 10:50:26 +01:00
func ( s Scope ) Add ( ctx domain . RequestContext , sp space . Space ) ( err error ) {
sp . UserID = ctx . UserID
2017-07-24 16:24:21 +01:00
sp . Created = time . Now ( ) . UTC ( )
sp . Revised = time . Now ( ) . UTC ( )
2017-07-26 10:50:26 +01:00
stmt , err := ctx . Transaction . Preparex ( "INSERT INTO label (refid, label, orgid, userid, type, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?)" )
2017-07-24 16:24:21 +01:00
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.
2017-07-26 10:50:26 +01:00
func ( s Scope ) Get ( ctx domain . RequestContext , id string ) ( sp space . Space , err error ) {
2017-07-24 16:24:21 +01:00
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
}
2017-07-26 10:50:26 +01:00
err = stmt . Get ( & sp , ctx . OrgID , id )
2017-07-24 16:24:21 +01:00
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.
2017-07-26 10:50:26 +01:00
func ( s Scope ) PublicSpaces ( ctx domain . RequestContext , orgID string ) ( sp [ ] space . Space , err error ) {
2017-07-24 16:24:21 +01:00
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.
2017-07-26 10:50:26 +01:00
func ( s Scope ) GetAll ( ctx domain . RequestContext ) ( sp [ ] space . Space , err error ) {
2017-07-24 16:24:21 +01:00
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 ,
2017-07-26 10:50:26 +01:00
ctx . OrgID ,
ctx . UserID ,
ctx . OrgID ,
ctx . OrgID ,
ctx . OrgID ,
ctx . OrgID ,
ctx . UserID )
2017-07-24 16:24:21 +01:00
if err != nil {
2017-07-26 10:50:26 +01:00
err = errors . Wrap ( err , fmt . Sprintf ( "Unable to execute select labels for org %s" , ctx . OrgID ) )
2017-07-24 16:24:21 +01:00
return
}
return
}
// Update saves space changes.
2017-07-26 10:50:26 +01:00
func ( s Scope ) Update ( ctx domain . RequestContext , sp space . Space ) ( err error ) {
2017-07-24 16:24:21 +01:00
sp . Revised = time . Now ( ) . UTC ( )
2017-07-26 10:50:26 +01:00
stmt , err := ctx . Transaction . PrepareNamed ( "UPDATE label SET label=:name, type=:type, userid=:userid, revised=:revised WHERE orgid=:orgid AND refid=:refid" )
2017-07-24 16:24:21 +01:00
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.
2017-07-26 10:50:26 +01:00
func ( s Scope ) ChangeOwner ( ctx domain . RequestContext , currentOwner , newOwner string ) ( err error ) {
stmt , err := ctx . Transaction . Preparex ( "UPDATE label SET userid=? WHERE userid=? AND orgid=?" )
2017-07-24 16:24:21 +01:00
defer streamutil . Close ( stmt )
if err != nil {
err = errors . Wrap ( err , fmt . Sprintf ( "unable to prepare change space owner for %s" , currentOwner ) )
return
}
2017-07-26 10:50:26 +01:00
_ , err = stmt . Exec ( newOwner , currentOwner , ctx . OrgID )
2017-07-24 16:24:21 +01:00
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.
2017-07-26 10:50:26 +01:00
func ( s Scope ) Viewers ( ctx domain . RequestContext ) ( v [ ] space . Viewer , err error ) {
2017-07-24 16:24:21 +01:00
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 `
2017-07-26 10:50:26 +01:00
err = s . Runtime . Db . Select ( & v , sql , ctx . OrgID )
2017-07-24 16:24:21 +01:00
return
}
// Delete removes space from the store.
2017-07-26 10:50:26 +01:00
func ( s Scope ) Delete ( ctx domain . RequestContext , id string ) ( rows int64 , err error ) {
2017-07-24 16:24:21 +01:00
b := mysql . BaseQuery { }
2017-07-26 10:50:26 +01:00
return b . DeleteConstrained ( ctx . Transaction , "label" , ctx . OrgID , id )
2017-07-24 16:24:21 +01:00
}
// AddRole inserts the given record into the labelrole database table.
2017-07-26 10:50:26 +01:00
func ( s Scope ) AddRole ( ctx domain . RequestContext , r space . Role ) ( err error ) {
2017-07-24 16:24:21 +01:00
r . Created = time . Now ( ) . UTC ( )
r . Revised = time . Now ( ) . UTC ( )
2017-07-26 10:50:26 +01:00
stmt , err := ctx . Transaction . Preparex ( "INSERT INTO labelrole (refid, labelid, orgid, userid, canview, canedit, created, revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?)" )
2017-07-24 16:24:21 +01:00
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.
2017-07-26 10:50:26 +01:00
func ( s Scope ) GetRoles ( ctx domain . RequestContext , labelID string ) ( r [ ] space . Role , err error ) {
2017-07-24 16:24:21 +01:00
query := ` SELECT id, refid, labelid, orgid, userid, canview, canedit, created, revised FROM labelrole WHERE orgid=? AND labelid=? ` // was + "GROUP BY userid"
2017-07-26 10:50:26 +01:00
err = s . Runtime . Db . Select ( & r , query , ctx . OrgID , labelID )
2017-07-24 16:24:21 +01:00
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.
2017-07-26 10:50:26 +01:00
func ( s Scope ) GetUserRoles ( ctx domain . RequestContext ) ( r [ ] space . Role , err error ) {
2017-07-24 16:24:21 +01:00
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 = ' ' ` ,
2017-07-26 10:50:26 +01:00
ctx . OrgID , ctx . UserID , ctx . OrgID )
2017-07-24 16:24:21 +01:00
if err == sql . ErrNoRows {
err = nil
}
if err != nil {
2017-07-26 10:50:26 +01:00
err = errors . Wrap ( err , fmt . Sprintf ( "unable to execute select for user space roles %s" , ctx . UserID ) )
2017-07-24 16:24:21 +01:00
return
}
return
}
// DeleteRole deletes the labelRoleID record from the labelrole table.
2017-07-26 10:50:26 +01:00
func ( s Scope ) DeleteRole ( ctx domain . RequestContext , roleID string ) ( rows int64 , err error ) {
2017-07-24 16:24:21 +01:00
b := mysql . BaseQuery { }
2017-07-26 10:50:26 +01:00
sql := fmt . Sprintf ( "DELETE FROM labelrole WHERE orgid='%s' AND refid='%s'" , ctx . OrgID , roleID )
2017-07-24 16:24:21 +01:00
2017-07-26 10:50:26 +01:00
return b . DeleteWhere ( ctx . Transaction , sql )
2017-07-24 16:24:21 +01:00
}
// DeleteSpaceRoles deletes records from the labelrole table which have the given space ID.
2017-07-26 10:50:26 +01:00
func ( s Scope ) DeleteSpaceRoles ( ctx domain . RequestContext , spaceID string ) ( rows int64 , err error ) {
2017-07-24 16:24:21 +01:00
b := mysql . BaseQuery { }
2017-07-26 10:50:26 +01:00
sql := fmt . Sprintf ( "DELETE FROM labelrole WHERE orgid='%s' AND labelid='%s'" , ctx . OrgID , spaceID )
2017-07-24 16:24:21 +01:00
2017-07-26 10:50:26 +01:00
return b . DeleteWhere ( ctx . Transaction , sql )
2017-07-24 16:24:21 +01:00
}
// DeleteUserSpaceRoles removes all roles for the specified user, for the specified space.
2017-07-26 10:50:26 +01:00
func ( s Scope ) DeleteUserSpaceRoles ( ctx domain . RequestContext , spaceID , userID string ) ( rows int64 , err error ) {
2017-07-24 16:24:21 +01:00
b := mysql . BaseQuery { }
sql := fmt . Sprintf ( "DELETE FROM labelrole WHERE orgid='%s' AND labelid='%s' AND userid='%s'" ,
2017-07-26 10:50:26 +01:00
ctx . OrgID , spaceID , userID )
2017-07-24 16:24:21 +01:00
2017-07-26 10:50:26 +01:00
return b . DeleteWhere ( ctx . Transaction , sql )
2017-07-24 16:24:21 +01:00
}
// MoveSpaceRoles changes the space ID for space role records from previousLabel to newLabel.
2017-07-26 10:50:26 +01:00
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=?" )
2017-07-24 16:24:21 +01:00
defer streamutil . Close ( stmt )
if err != nil {
err = errors . Wrap ( err , fmt . Sprintf ( "unable to prepare move space roles for label %s" , previousLabel ) )
return
}
2017-07-26 10:50:26 +01:00
_ , err = stmt . Exec ( newLabel , previousLabel , ctx . OrgID )
2017-07-24 16:24:21 +01:00
if err != nil {
err = errors . Wrap ( err , fmt . Sprintf ( "unable to execute move space roles for label %s" , previousLabel ) )
}
return
}