Reworking stuff
This commit is contained in:
256
pkgs/db/accounts.go
Normal file
256
pkgs/db/accounts.go
Normal file
@@ -0,0 +1,256 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// AccountCreate writes a user to database
|
||||
func (d Db) AccountCreate(input AccountCreateInput) (CreatedAccount, error) {
|
||||
d.Log.Context = []interface{}{
|
||||
"accountName", input.Name,
|
||||
"id", input.ID,
|
||||
}
|
||||
accountSQL := "INSERT INTO accounts (id, name, \"apiKey\", password) VALUES($1,$2,$3,$4);"
|
||||
|
||||
_, err := d.DbPool.Exec(context.Background(), accountSQL, input.ID, input.Name, input.APIKey, input.Password)
|
||||
if err != nil {
|
||||
if strings.HasPrefix(err.Error(), "ERROR: duplicate key") {
|
||||
d.Log.Debug("Duplicate name in accounts database")
|
||||
} else {
|
||||
d.Log.Warn("Database error when trying to add account", "err", err.Error())
|
||||
}
|
||||
|
||||
return CreatedAccount{}, err
|
||||
}
|
||||
|
||||
d.Log.Verbose("Added account to database", "id", input.ID)
|
||||
|
||||
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 {
|
||||
d.Log.Warn("Could not create new Uuid", "err", uuidErr.Error())
|
||||
return CreatedAccount{}, uuidErr
|
||||
}
|
||||
|
||||
_, err := d.DbPool.Exec(context.Background(), accountFieldsSQL, newFieldID, input.ID, field.Name, field.Values)
|
||||
if err != nil {
|
||||
//if strings.HasPrefix(err.Error(), "ERROR: duplicate key") {
|
||||
d.Log.Warn("Database error when trying to add account field", "err", err.Error(), "accountID", input.ID, "fieldName", field.Name, "fieldvalues", field.Values)
|
||||
// }
|
||||
}
|
||||
|
||||
d.Log.Debug("Added account field", "accountID", input.ID, "fieldName", field.Name, "fieldValues", field.Values)
|
||||
}
|
||||
|
||||
return CreatedAccount{
|
||||
ID: input.ID,
|
||||
Name: input.Name,
|
||||
APIKey: input.APIKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d Db) AccountDel(accountID string) error {
|
||||
d.Log.Context = []interface{}{
|
||||
"accountID", accountID,
|
||||
}
|
||||
d.Log.Verbose("Trying to delete account")
|
||||
|
||||
_, 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())
|
||||
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())
|
||||
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())
|
||||
return err
|
||||
}
|
||||
|
||||
if string(res) == "DELETE 0" {
|
||||
d.Log.Debug("Tried to delete account, but none exists")
|
||||
err := errors.New("no account found for given accountID")
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AccountGet fetches an account from the database
|
||||
func (d Db) AccountGet(accountID string, APIKey string, name string) (Account, error) {
|
||||
d.Log.Context = []interface{}{
|
||||
"accountID", accountID,
|
||||
"len(APIKey)", len(APIKey),
|
||||
"name", name,
|
||||
}
|
||||
d.Log.Debug("Trying to get account")
|
||||
|
||||
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
|
||||
} else if name != "" {
|
||||
accountSQL = accountSQL + "name = $1"
|
||||
searchParam = name
|
||||
} else {
|
||||
d.Log.Debug("No get criteria entered, returning empty response without calling the database")
|
||||
|
||||
return Account{}, errors.New("no rows in result set")
|
||||
}
|
||||
|
||||
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" {
|
||||
d.Log.Debug("No account found")
|
||||
return Account{}, accountErr
|
||||
}
|
||||
|
||||
d.Log.Error("Database error when fetching account", "err", accountErr.Error())
|
||||
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 {
|
||||
d.Log.Error("Database error when fetching account fields", "err", accountErr.Error())
|
||||
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 {
|
||||
d.Log.Error("Could not get name or value from database row", "err", err.Error())
|
||||
return Account{}, err
|
||||
}
|
||||
account.Fields[name] = value
|
||||
}
|
||||
|
||||
return account, nil
|
||||
}
|
||||
|
||||
// func (d Db) AccountsGet() ([]Account, error) {
|
||||
// d.Log.Debug("Trying to get accounts", "name", name)
|
||||
|
||||
// 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
|
||||
// } else if name != "" {
|
||||
// accountSQL = accountSQL + "name = $1"
|
||||
// searchParam = name
|
||||
// } else {
|
||||
// d.Log.Debug("No get criteria entered, returning empty response without calling the database")
|
||||
|
||||
// return Account{}, errors.New("no rows in result set")
|
||||
// }
|
||||
|
||||
// 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" {
|
||||
// d.Log.Debug("No account found", "accountID", accountID, "APIKey", len(APIKey))
|
||||
// return Account{}, accountErr
|
||||
// }
|
||||
|
||||
// d.Log.Error("Database error when fetching account", "err", accountErr.Error(), "accountID", accountID, "APIKey", len(APIKey))
|
||||
// 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 {
|
||||
// d.Log.Error("Database error when fetching account fields", "err", accountErr.Error(), "accountID", accountID, "APIKey", len(APIKey))
|
||||
// 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 {
|
||||
// d.Log.Error("Could not get name or value from database row", "err", err.Error(), "accountID", accountID, "APIKey", len(APIKey))
|
||||
// return Account{}, err
|
||||
// }
|
||||
// account.Fields[name] = value
|
||||
// }
|
||||
|
||||
// return account, nil
|
||||
// }
|
||||
|
||||
func (d Db) AccountUpdateFields(accountID string, fields []AccountCreateInputFields) (Account, error) {
|
||||
d.Log.Context = []interface{}{
|
||||
"accountID", accountID,
|
||||
"fields", fields,
|
||||
}
|
||||
|
||||
// Begin database transaction
|
||||
conn, err := d.DbPool.Acquire(context.Background())
|
||||
if err != nil {
|
||||
d.Log.Error("Could not acquire database connection", "err", err.Error())
|
||||
return Account{}, err
|
||||
}
|
||||
|
||||
tx, err := conn.Begin(context.Background())
|
||||
if err != nil {
|
||||
d.Log.Error("Could not begin database transaction", "err", err.Error())
|
||||
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())
|
||||
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.Error("Could not create new Uuid", "err", err.Error())
|
||||
return Account{}, err
|
||||
}
|
||||
|
||||
_, 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(), "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, "", "")
|
||||
}
|
||||
61
pkgs/db/renewalTokens.go
Normal file
61
pkgs/db/renewalTokens.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitea.larvit.se/pwrpln/auth-api/pkgs/utils"
|
||||
)
|
||||
|
||||
// RenewalTokenCreate obtain a new renewal token
|
||||
func (d Db) RenewalTokenCreate(accountID string) (string, error) {
|
||||
d.Log.Context = []interface{}{
|
||||
"accountID", accountID,
|
||||
}
|
||||
|
||||
d.Log.Debug("Creating new renewal token")
|
||||
|
||||
newToken := utils.RandString(60)
|
||||
|
||||
insertSQL := "INSERT INTO \"renewalTokens\" (\"accountId\",token) VALUES($1,$2);"
|
||||
_, insertErr := d.DbPool.Exec(context.Background(), insertSQL, accountID, newToken)
|
||||
if insertErr != nil {
|
||||
d.Log.Error("Could not insert into database table \"renewalTokens\"", "err", insertErr.Error())
|
||||
return "", insertErr
|
||||
}
|
||||
|
||||
return newToken, nil
|
||||
}
|
||||
|
||||
// RenewalTokenGet checks if a valid renewal token exists in database
|
||||
func (d Db) RenewalTokenGet(token string) (string, error) {
|
||||
d.Log.Debug("Trying to get a renewal token")
|
||||
|
||||
sql := "SELECT \"accountId\" FROM \"renewalTokens\" WHERE exp >= now() AND token = $1"
|
||||
|
||||
var foundAccountID string
|
||||
err := d.DbPool.QueryRow(context.Background(), sql, token).Scan(&foundAccountID)
|
||||
if err != nil {
|
||||
if err.Error() == "no rows in result set" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
d.Log.Error("Database error when fetching renewal token", "err", err.Error())
|
||||
return "", err
|
||||
}
|
||||
|
||||
return foundAccountID, nil
|
||||
}
|
||||
|
||||
// RenewalTokenRm removes a renewal token from the database
|
||||
func (d Db) RenewalTokenRm(token string) error {
|
||||
d.Log.Debug("Trying to remove a renewal token")
|
||||
|
||||
sql := "DELETE FROM \"renewalTokens\" WHERE token = $1"
|
||||
_, err := d.DbPool.Exec(context.Background(), sql, token)
|
||||
if err != nil {
|
||||
d.Log.Error("Database error when trying to remove token", "err", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
46
pkgs/db/types.go
Normal file
46
pkgs/db/types.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gitea.larvit.se/pwrpln/go_log"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
)
|
||||
|
||||
// Account is an account as represented in the database
|
||||
type Account struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Created time.Time `json:"created"`
|
||||
Fields map[string][]string `json:"fields"`
|
||||
Name string `json:"name"`
|
||||
Password string `json:"-"`
|
||||
}
|
||||
|
||||
// CreatedAccount is a newly created account in the system
|
||||
type CreatedAccount struct {
|
||||
ID uuid.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
APIKey string `json:"apiKey"`
|
||||
}
|
||||
|
||||
// AccountCreateInputFields yes
|
||||
type AccountCreateInputFields struct {
|
||||
Name string
|
||||
Values []string
|
||||
}
|
||||
|
||||
// AccountCreateInput is used as input struct for database creation of account
|
||||
type AccountCreateInput struct {
|
||||
ID uuid.UUID
|
||||
Name string
|
||||
APIKey string
|
||||
Fields []AccountCreateInputFields
|
||||
Password string
|
||||
}
|
||||
|
||||
// Db struct
|
||||
type Db struct {
|
||||
DbPool *pgxpool.Pool
|
||||
Log go_log.Log
|
||||
}
|
||||
Reference in New Issue
Block a user