2021-01-02 12:09:16 +01:00
package db
import (
"context"
2021-06-24 00:42:54 +02:00
"errors"
2021-01-02 12:09:16 +01:00
"strings"
"github.com/google/uuid"
)
// AccountCreate writes a user to database
func ( d Db ) AccountCreate ( input AccountCreateInput ) ( CreatedAccount , error ) {
2021-01-03 18:21:42 +01:00
accountSQL := "INSERT INTO accounts (id, name, \"apiKey\", password) VALUES($1,$2,$3,$4);"
2021-01-02 12:09:16 +01:00
2021-01-03 18:21:42 +01:00
_ , err := d . DbPool . Exec ( context . Background ( ) , accountSQL , input . ID , input . Name , input . APIKey , input . Password )
2021-01-02 12:09:16 +01:00
if err != nil {
if strings . HasPrefix ( err . Error ( ) , "ERROR: duplicate key" ) {
2021-06-22 22:52:48 +02:00
d . Log . Debug ( "Duplicate name in accounts database" , "name" , input . Name )
2021-01-02 12:09:16 +01:00
} else {
2021-06-22 22:52:48 +02:00
d . Log . Error ( "Database error when trying to add account" , "err" , err . Error ( ) )
2021-01-02 12:09:16 +01:00
}
return CreatedAccount { } , err
}
2021-06-22 22:52:48 +02:00
d . Log . Info ( "Added account to database" , "id" , input . ID , "name" , input . Name )
2021-01-02 12:09:16 +01:00
accountFieldsSQL := "INSERT INTO \"accountsFields\" (id, \"accountId\", name, value) VALUES($1,$2,$3,$4);"
for _ , field := range input . Fields {
newFieldID , uuidErr := uuid . NewRandom ( )
if uuidErr != nil {
2021-06-22 22:52:48 +02:00
d . Log . Fatal ( "Could not create new Uuid" , "err" , uuidErr . Error ( ) )
2021-01-02 12:09:16 +01:00
}
_ , err := d . DbPool . Exec ( context . Background ( ) , accountFieldsSQL , newFieldID , input . ID , field . Name , field . Values )
if err != nil {
2021-06-24 01:55:47 +02:00
//if strings.HasPrefix(err.Error(), "ERROR: duplicate key") {
d . Log . Error ( "Database error when trying to add account field" , "err" , err . Error ( ) , "accountID" , input . ID , "fieldName" , field . Name , "fieldvalues" , field . Values )
// }
2021-01-02 12:09:16 +01:00
}
2021-06-24 01:55:47 +02:00
d . Log . Debug ( "Added account field" , "accountID" , input . ID , "fieldName" , field . Name , "fieldValues" , field . Values )
2021-01-02 12:09:16 +01:00
}
return CreatedAccount {
2021-01-03 18:21:42 +01:00
ID : input . ID ,
Name : input . Name ,
APIKey : input . APIKey ,
2021-01-02 12:09:16 +01:00
} , nil
}
2021-01-03 18:21:42 +01:00
2021-06-24 00:42:54 +02:00
func ( d Db ) AccountDel ( accountID string ) error {
d . Log . Info ( "Trying to delete account" , "accountID" , accountID )
_ , renewalTokensErr := d . DbPool . Exec ( context . Background ( ) , "DELETE FROM \"renewalTokens\" WHERE \"accountId\" = $1;" , accountID )
if renewalTokensErr != nil {
d . Log . Error ( "Could not remove renewal tokens for account" , "err" , renewalTokensErr . Error ( ) , "accountID" , accountID )
return renewalTokensErr
}
_ , fieldsErr := d . DbPool . Exec ( context . Background ( ) , "DELETE FROM \"accountsFields\" WHERE \"accountId\" = $1;" , accountID )
if fieldsErr != nil {
d . Log . Error ( "Could not remove account fields" , "err" , fieldsErr . Error ( ) , "accountID" , accountID )
return fieldsErr
}
res , err := d . DbPool . Exec ( context . Background ( ) , "DELETE FROM accounts WHERE id = $1" , accountID )
if err != nil {
d . Log . Error ( "Could not remove account" , "err" , err . Error ( ) , "accountID" , accountID )
return err
}
if string ( res ) == "DELETE 0" {
d . Log . Info ( "Tried to delete account, but none exists" , "accountID" , accountID )
err := errors . New ( "No account found for given accountID" )
return err
}
return nil
}
2021-01-03 18:21:42 +01:00
// AccountGet fetches an account from the database
2021-01-05 16:23:18 +01:00
func ( d Db ) AccountGet ( accountID string , APIKey string , Name string ) ( Account , error ) {
2021-06-22 22:52:48 +02:00
d . Log . Debug ( "Trying to get account" , "accountID" , accountID , "len(APIKey)" , len ( APIKey ) )
2021-01-03 18:21:42 +01:00
var account Account
var searchParam string
accountSQL := "SELECT id, created, name, \"password\" FROM accounts WHERE "
if accountID != "" {
accountSQL = accountSQL + "id = $1"
searchParam = accountID
} else if APIKey != "" {
accountSQL = accountSQL + "\"apiKey\" = $1"
searchParam = APIKey
2021-01-05 16:23:18 +01:00
} else if Name != "" {
accountSQL = accountSQL + "name = $1"
searchParam = Name
2021-01-03 18:21:42 +01:00
}
accountErr := d . DbPool . QueryRow ( context . Background ( ) , accountSQL , searchParam ) . Scan ( & account . ID , & account . Created , & account . Name , & account . Password )
if accountErr != nil {
if accountErr . Error ( ) == "no rows in result set" {
2021-06-22 22:52:48 +02:00
d . Log . Debug ( "No account found" , "accountID" , accountID , "APIKey" , len ( APIKey ) )
2021-01-03 18:21:42 +01:00
return Account { } , accountErr
}
2021-06-22 22:52:48 +02:00
d . Log . Error ( "Database error when fetching account" , "err" , accountErr . Error ( ) , "accountID" , accountID , "APIKey" , len ( APIKey ) )
2021-01-03 18:21:42 +01:00
return Account { } , accountErr
}
fieldsSQL := "SELECT name, value FROM \"accountsFields\" WHERE \"accountId\" = $1"
rows , fieldsErr := d . DbPool . Query ( context . Background ( ) , fieldsSQL , account . ID )
if fieldsErr != nil {
2021-06-22 22:52:48 +02:00
d . Log . Error ( "Database error when fetching account fields" , "err" , accountErr . Error ( ) , "accountID" , accountID , "APIKey" , len ( APIKey ) )
2021-01-03 18:21:42 +01:00
return Account { } , fieldsErr
}
account . Fields = make ( map [ string ] [ ] string )
for rows . Next ( ) {
var name string
var value [ ] string
err := rows . Scan ( & name , & value )
if err != nil {
2021-06-22 22:52:48 +02:00
d . Log . Error ( "Could not get name or value from database row" , "err" , err . Error ( ) , "accountID" , accountID , "APIKey" , len ( APIKey ) )
2021-01-03 18:21:42 +01:00
return Account { } , err
}
account . Fields [ name ] = value
}
return account , nil
}
2021-06-24 01:55:47 +02:00
func ( d Db ) AccountUpdateFields ( accountID string , fields [ ] AccountCreateInputFields ) ( Account , error ) {
// Begin database transaction
conn , err := d . DbPool . Acquire ( context . Background ( ) )
if err != nil {
d . Log . Error ( "Could not acquire database connection" , "err" , err . Error ( ) , "accountID" , accountID )
return Account { } , err
}
tx , err := conn . Begin ( context . Background ( ) )
if err != nil {
d . Log . Error ( "Could not begin database transaction" , "err" , err . Error ( ) , "accountID" , accountID )
return Account { } , err
}
// Rollback is safe to call even if the tx is already closed, so if
// the tx commits successfully, this is a no-op
defer tx . Rollback ( context . Background ( ) )
_ , err = tx . Exec ( context . Background ( ) , "DELETE FROM \"accountsFields\" WHERE \"accountId\" = $1;" , accountID )
if err != nil {
d . Log . Error ( "Could not delete previous fields" , "err" , err . Error ( ) , "accountID" , accountID )
return Account { } , err
}
accountFieldsSQL := "INSERT INTO \"accountsFields\" (id, \"accountId\", name, value) VALUES($1,$2,$3,$4);"
for _ , field := range fields {
newFieldID , err := uuid . NewRandom ( )
if err != nil {
d . Log . Fatal ( "Could not create new Uuid" , "err" , err . Error ( ) )
}
_ , err = tx . Exec ( context . Background ( ) , accountFieldsSQL , newFieldID , accountID , field . Name , field . Values )
if err != nil {
d . Log . Error ( "Database error when trying to add account field" , "err" , err . Error ( ) , "accountID" , accountID , "fieldName" , field . Name , "fieldvalues" , field . Values )
}
d . Log . Debug ( "Added account field" , "accountID" , accountID , "fieldName" , field . Name , "fieldValues" , field . Values )
}
err = tx . Commit ( context . Background ( ) )
if err != nil {
d . Log . Error ( "Database error when tying to commit" , "err" , err . Error ( ) )
return Account { } , err
}
return d . AccountGet ( accountID , "" , "" )
}