2018-10-19 15:31:41 -04:00
package db
import (
"database/sql"
"errors"
"github.com/openaccounting/oa-server/core/model/types"
"github.com/openaccounting/oa-server/core/util"
"time"
)
type OrgInterface interface {
CreateOrg ( * types . Org , string , [ ] * types . Account ) error
UpdateOrg ( * types . Org ) error
GetOrg ( string , string ) ( * types . Org , error )
GetOrgs ( string ) ( [ ] * types . Org , error )
GetOrgUserIds ( string ) ( [ ] string , error )
InsertInvite ( * types . Invite ) error
AcceptInvite ( * types . Invite , string ) error
GetInvites ( string ) ( [ ] * types . Invite , error )
GetInvite ( string ) ( * types . Invite , error )
DeleteInvite ( string ) error
}
2019-06-27 16:43:18 -04:00
const orgFields = "LOWER(HEX(o.id)),o.inserted,o.updated,o.name,o.currency,o.`precision`,o.timezone"
2018-10-19 15:31:41 -04:00
const inviteFields = "i.id,LOWER(HEX(i.orgId)),i.inserted,i.updated,i.email,i.accepted"
func ( db * DB ) CreateOrg ( org * types . Org , userId string , accounts [ ] * types . Account ) ( err error ) {
tx , err := db . Begin ( )
if err != nil {
return
}
defer func ( ) {
if p := recover ( ) ; p != nil {
tx . Rollback ( )
panic ( p ) // re-throw panic after Rollback
} else if err != nil {
tx . Rollback ( )
} else {
err = tx . Commit ( )
}
} ( )
org . Inserted = time . Now ( )
org . Updated = org . Inserted
// create org
2019-06-27 16:43:18 -04:00
query1 := "INSERT INTO org(id,inserted,updated,name,currency,`precision`,timezone) VALUES(UNHEX(?),?,?,?,?,?,?)"
2018-10-19 15:31:41 -04:00
res , err := tx . Exec (
query1 ,
org . Id ,
util . TimeToMs ( org . Inserted ) ,
util . TimeToMs ( org . Updated ) ,
org . Name ,
org . Currency ,
org . Precision ,
2019-06-27 16:43:18 -04:00
org . Timezone ,
2018-10-19 15:31:41 -04:00
)
if err != nil {
return
}
// associate user with org
query2 := "INSERT INTO userorg(userId,orgId,admin) VALUES(UNHEX(?),UNHEX(?), 1)"
res , err = tx . Exec ( query2 , userId , org . Id )
if err != nil {
return
}
_ , err = res . LastInsertId ( )
if err != nil {
return
}
// create Accounts: Root, Assets, Liabilities, Equity, Income, Expenses
for _ , account := range accounts {
query := "INSERT INTO account(id,orgId,inserted,updated,name,parent,currency,`precision`,debitBalance) VALUES (UNHEX(?),UNHEX(?),?,?,?,UNHEX(?),?,?,?)"
if _ , err = tx . Exec (
query ,
account . Id ,
org . Id ,
util . TimeToMs ( org . Inserted ) ,
util . TimeToMs ( org . Updated ) ,
account . Name ,
account . Parent ,
account . Currency ,
account . Precision ,
account . DebitBalance ,
) ; err != nil {
return
}
}
permissionId , err := util . NewGuid ( )
if err != nil {
return
}
// Grant root permission to user
query3 := "INSERT INTO permission (id,userId,orgId,accountId,type,inserted,updated) VALUES(UNHEX(?),UNHEX(?),UNHEX(?),UNHEX(?),?,?,?)"
_ , err = tx . Exec (
query3 ,
permissionId ,
userId ,
org . Id ,
accounts [ 0 ] . Id ,
0 ,
util . TimeToMs ( org . Inserted ) ,
util . TimeToMs ( org . Updated ) ,
)
return
}
func ( db * DB ) UpdateOrg ( org * types . Org ) error {
org . Updated = time . Now ( )
2019-06-27 16:43:18 -04:00
query := "UPDATE org SET updated = ?, name = ?, timezone = ? WHERE id = UNHEX(?)"
2018-10-19 15:31:41 -04:00
_ , err := db . Exec (
query ,
util . TimeToMs ( org . Updated ) ,
org . Name ,
2019-06-27 16:43:18 -04:00
org . Timezone ,
2018-10-19 15:31:41 -04:00
org . Id ,
)
return err
}
func ( db * DB ) GetOrg ( orgId string , userId string ) ( * types . Org , error ) {
var o types . Org
var inserted int64
var updated int64
err := db . QueryRow ( "SELECT " + orgFields + " FROM org o JOIN userorg ON userorg.orgId = o.id WHERE o.id = UNHEX(?) AND userorg.userId = UNHEX(?)" , orgId , userId ) .
2019-06-27 16:43:18 -04:00
Scan ( & o . Id , & inserted , & updated , & o . Name , & o . Currency , & o . Precision , & o . Timezone )
2018-10-19 15:31:41 -04:00
switch {
case err == sql . ErrNoRows :
return nil , errors . New ( "Org not found" )
case err != nil :
return nil , err
default :
o . Inserted = util . MsToTime ( inserted )
o . Updated = util . MsToTime ( updated )
return & o , nil
}
}
func ( db * DB ) GetOrgs ( userId string ) ( [ ] * types . Org , error ) {
rows , err := db . Query ( "SELECT " + orgFields + " from org o JOIN userorg ON userorg.orgId = o.id WHERE userorg.userId = UNHEX(?)" , userId )
if err != nil {
return nil , err
}
defer rows . Close ( )
orgs := make ( [ ] * types . Org , 0 )
for rows . Next ( ) {
o := new ( types . Org )
var inserted int64
var updated int64
2019-06-27 16:43:18 -04:00
err = rows . Scan ( & o . Id , & inserted , & updated , & o . Name , & o . Currency , & o . Precision , & o . Timezone )
2018-10-19 15:31:41 -04:00
if err != nil {
return nil , err
}
o . Inserted = util . MsToTime ( inserted )
o . Updated = util . MsToTime ( updated )
orgs = append ( orgs , o )
}
err = rows . Err ( )
if err != nil {
return nil , err
}
return orgs , nil
}
func ( db * DB ) GetOrgUserIds ( orgId string ) ( [ ] string , error ) {
rows , err := db . Query ( "SELECT LOWER(HEX(userId)) FROM userorg WHERE orgId = UNHEX(?)" , orgId )
if err != nil {
return nil , err
}
defer rows . Close ( )
userIds := make ( [ ] string , 0 )
for rows . Next ( ) {
var userId string
err = rows . Scan ( & userId )
if err != nil {
return nil , err
}
userIds = append ( userIds , userId )
}
err = rows . Err ( )
if err != nil {
return nil , err
}
return userIds , nil
}
func ( db * DB ) InsertInvite ( invite * types . Invite ) error {
invite . Inserted = time . Now ( )
invite . Updated = invite . Inserted
query := "INSERT INTO invite(id,orgId,inserted,updated,email,accepted) VALUES(?,UNHEX(?),?,?,?,?)"
_ , err := db . Exec (
query ,
invite . Id ,
invite . OrgId ,
util . TimeToMs ( invite . Inserted ) ,
util . TimeToMs ( invite . Updated ) ,
invite . Email ,
false ,
)
return err
}
func ( db * DB ) AcceptInvite ( invite * types . Invite , userId string ) error {
invite . Updated = time . Now ( )
// Get root account for permission
rootAccount , err := db . GetRootAccount ( invite . OrgId )
if err != nil {
return err
}
tx , err := db . Begin ( )
if err != nil {
return err
}
defer func ( ) {
if p := recover ( ) ; p != nil {
tx . Rollback ( )
panic ( p ) // re-throw panic after Rollback
} else if err != nil {
tx . Rollback ( )
} else {
err = tx . Commit ( )
}
} ( )
// associate user with org
query1 := "INSERT INTO userorg(userId,orgId,admin) VALUES(UNHEX(?),UNHEX(?), 0)"
_ , err = tx . Exec ( query1 , userId , invite . OrgId )
if err != nil {
return err
}
query2 := "UPDATE invite SET accepted = 1, updated = ? WHERE id = ?"
_ , err = tx . Exec ( query2 , util . TimeToMs ( invite . Updated ) , invite . Id )
// Grant root permission to user
permissionId , err := util . NewGuid ( )
if err != nil {
return err
}
query3 := "INSERT INTO permission (id,userId,orgId,accountId,type,inserted,updated) VALUES(UNHEX(?),UNHEX(?),UNHEX(?),UNHEX(?),?,?,?)"
_ , err = tx . Exec (
query3 ,
permissionId ,
userId ,
invite . OrgId ,
rootAccount . Id ,
0 ,
util . TimeToMs ( invite . Updated ) ,
util . TimeToMs ( invite . Updated ) ,
)
return err
}
func ( db * DB ) GetInvites ( orgId string ) ( [ ] * types . Invite , error ) {
// don't include expired invoices
cutoff := util . TimeToMs ( time . Now ( ) ) - 7 * 24 * 60 * 60 * 1000
rows , err := db . Query ( "SELECT " + inviteFields + " FROM invite i WHERE orgId = UNHEX(?) AND inserted > ?" , orgId , cutoff )
if err != nil {
return nil , err
}
defer rows . Close ( )
invites := make ( [ ] * types . Invite , 0 )
for rows . Next ( ) {
i := new ( types . Invite )
var inserted int64
var updated int64
err = rows . Scan ( & i . Id , & i . OrgId , & inserted , & updated , & i . Email , & i . Accepted )
if err != nil {
return nil , err
}
i . Inserted = util . MsToTime ( inserted )
i . Updated = util . MsToTime ( updated )
invites = append ( invites , i )
}
err = rows . Err ( )
if err != nil {
return nil , err
}
return invites , nil
}
func ( db * DB ) GetInvite ( id string ) ( * types . Invite , error ) {
var i types . Invite
var inserted int64
var updated int64
err := db . QueryRow ( "SELECT " + inviteFields + " FROM invite i WHERE i.id = ?" , id ) .
Scan ( & i . Id , & i . OrgId , & inserted , & updated , & i . Email , & i . Accepted )
switch {
case err == sql . ErrNoRows :
return nil , errors . New ( "Invite not found" )
case err != nil :
return nil , err
default :
i . Inserted = util . MsToTime ( inserted )
i . Updated = util . MsToTime ( updated )
return & i , nil
}
}
func ( db * DB ) DeleteInvite ( id string ) error {
query := "DELETE FROM invite WHERE id = ?"
_ , err := db . Exec (
query ,
id ,
)
return err
}