435 lines
13 KiB
Go
435 lines
13 KiB
Go
/*
|
|
___ ___ ___ _ __ __ _ ___
|
|
/ __/ _ \ / _ \| '_ \ / _` |/ _ \
|
|
| (_| (_) | (_) | |_) | (_| | (_) |
|
|
\___\___/ \___/| .__/ \__, |\___/
|
|
| | __/ |
|
|
|_| |___/
|
|
*/
|
|
|
|
package storage
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
_ "github.com/lib/pq"
|
|
"github.com/spf13/viper"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type PostgresqlStorage struct {
|
|
DbConnection *sql.DB
|
|
}
|
|
|
|
func NewPostgresqlStorage(cfg *viper.Viper) (PostgresqlStorage, error) {
|
|
var (
|
|
host = cfg.GetString("storage.db.psql.host")
|
|
port = cfg.GetString("storage.db.psql.port")
|
|
user = cfg.GetString("storage.db.psql.user")
|
|
password = cfg.GetString("storage.db.psql.password")
|
|
dbname = cfg.GetString("storage.db.psql.dbname")
|
|
)
|
|
portInt, _ := strconv.Atoi(port)
|
|
psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, portInt,
|
|
user, password, dbname)
|
|
db, err := sql.Open("postgres", psqlconn)
|
|
if err != nil {
|
|
fmt.Println("error", err)
|
|
return PostgresqlStorage{}, fmt.Errorf("connection to postgresql failed")
|
|
}
|
|
err = db.Ping()
|
|
if err != nil {
|
|
return PostgresqlStorage{}, fmt.Errorf("connection to postgresql database failed")
|
|
}
|
|
return PostgresqlStorage{
|
|
DbConnection: db,
|
|
}, nil
|
|
}
|
|
|
|
func (psql PostgresqlStorage) GetAccount(id string) (*Account, error) {
|
|
var (
|
|
data, metadata, emailValidation, phoneValidation []byte
|
|
)
|
|
account := &Account{}
|
|
stmtAccounts, err := psql.DbConnection.Prepare("" +
|
|
"SELECT id, namespace, data, " +
|
|
"metadata, username, password, email, email_validation, " +
|
|
"phone_number, phone_number_validation FROM accounts a JOIN " +
|
|
"account_auth auth ON id = account_id WHERE id = $1")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("psql connection failed")
|
|
}
|
|
defer stmtAccounts.Close()
|
|
err = stmtAccounts.QueryRow(id).Scan(&account.ID,
|
|
&account.Namespace,
|
|
&data,
|
|
&metadata,
|
|
&account.Authentication.Local.Username,
|
|
&account.Authentication.Local.Password,
|
|
&account.Authentication.Local.Email,
|
|
&emailValidation,
|
|
&account.Authentication.Local.PhoneNumber,
|
|
&phoneValidation)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("psql select account query failed")
|
|
}
|
|
err = json.Unmarshal(data, &account.Data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(metadata, &account.Metadata)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(emailValidation, &account.Authentication.Local.EmailValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(phoneValidation, &account.Authentication.Local.PhoneNumberValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return account, nil
|
|
}
|
|
|
|
func (psql PostgresqlStorage) LocalAuthentication(namespace string, username string, email string,
|
|
phone_number string) (*Account, error) {
|
|
account := &Account{}
|
|
var (
|
|
data, metadata, emailValidation, phoneValidation []byte
|
|
)
|
|
if username != "" {
|
|
usernameStmt, err := psql.DbConnection.Prepare("SELECT id, namespace, data, metadata, username, " +
|
|
"password, email, email_validation, phone_number, phone_number_validation " +
|
|
"FROM accounts INNER JOIN account_auth ON accounts.id = account_auth.account_id WHERE " +
|
|
"namespace = $1 AND username = $2;")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = usernameStmt.QueryRow(namespace, username).Scan(
|
|
&account.ID,
|
|
&account.Namespace, &data, &metadata,
|
|
&account.Authentication.Local.Username,
|
|
&account.Authentication.Local.Password,
|
|
&account.Authentication.Local.Email,
|
|
&emailValidation, &account.Authentication.Local.PhoneNumber,
|
|
&phoneValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(metadata, &account.Metadata)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(data, &account.Data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(emailValidation, &account.Authentication.Local.EmailValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(phoneValidation, &account.Authentication.Local.PhoneNumberValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return account, nil
|
|
} else if email != "" {
|
|
account.Authentication.Local.Email = email
|
|
emailStmt, err := psql.DbConnection.Prepare("SELECT id, namespace, data, metadata, username, " +
|
|
"password, email_validation, phone_number, phone_number_validation " +
|
|
"FROM accounts INNER JOIN account_auth ON " +
|
|
"accounts.id = account_auth.account_id WHERE namespace = $1 AND email = $2;")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = emailStmt.QueryRow(namespace, email).Scan(
|
|
&account.ID,
|
|
&account.Namespace,
|
|
&data, &metadata,
|
|
&account.Authentication.Local.Username,
|
|
&account.Authentication.Local.Password,
|
|
&emailValidation,
|
|
&account.Authentication.Local.PhoneNumber,
|
|
&phoneValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(metadata, &account.Metadata)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(data, &account.Data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(emailValidation, &account.Authentication.Local.EmailValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(phoneValidation, &account.Authentication.Local.PhoneNumberValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return account, nil
|
|
} else if phone_number != "" {
|
|
account.Authentication.Local.PhoneNumber = phone_number
|
|
phoneStmt, err := psql.DbConnection.Prepare("SELECT id, namespace, " +
|
|
"data, metadata, username, password, email, " +
|
|
"email_validation, phone_number_validation FROM accounts " +
|
|
"INNER JOIN account_auth ON accounts.id = account_auth.account_id WHERE " +
|
|
"namespace = $1 AND phone_number = $2;")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = phoneStmt.QueryRow(namespace, phone_number).Scan(&account.ID,
|
|
&account.Namespace,
|
|
&data,
|
|
&metadata,
|
|
&account.Authentication.Local.Username,
|
|
&account.Authentication.Local.Password,
|
|
&account.Authentication.Local.Email,
|
|
&emailValidation,
|
|
&phoneValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(metadata, &account.Metadata)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(data, &account.Data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(emailValidation, &account.Authentication.Local.EmailValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(phoneValidation, &account.Authentication.Local.PhoneNumberValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return account, nil
|
|
}
|
|
return nil, fmt.Errorf("localauthentication func error PSQL")
|
|
}
|
|
|
|
func (psql PostgresqlStorage) GetAccounts(namespaces []string) ([]Account, error) {
|
|
var accounts []Account
|
|
namespacesStr := "'" + strings.Join(namespaces, "', '") + "'"
|
|
query := `
|
|
SELECT accounts.id, accounts.namespace, accounts.data, accounts.metadata,
|
|
account_auth.username, account_auth.password,
|
|
account_auth.email, account_auth.email_validation,
|
|
account_auth.phone_number, account_auth.phone_number_validation
|
|
FROM accounts
|
|
INNER JOIN account_auth ON accounts.id = account_auth.account_id
|
|
WHERE accounts.namespace IN (%s)
|
|
`
|
|
query = fmt.Sprintf(query, namespacesStr)
|
|
rows, err := psql.DbConnection.Query(query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var account Account
|
|
var dataBytes []byte
|
|
var metadataBytes []byte
|
|
var emailValidationBytes []byte
|
|
var phoneNumberValidationBytes []byte
|
|
err := rows.Scan(
|
|
&account.ID,
|
|
&account.Namespace,
|
|
&dataBytes,
|
|
&metadataBytes,
|
|
&account.Authentication.Local.Username,
|
|
&account.Authentication.Local.Password,
|
|
&account.Authentication.Local.Email,
|
|
&emailValidationBytes,
|
|
&account.Authentication.Local.PhoneNumber,
|
|
&phoneNumberValidationBytes,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = json.Unmarshal(dataBytes, &account.Data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = json.Unmarshal(metadataBytes, &account.Metadata)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = json.Unmarshal(emailValidationBytes, &account.Authentication.Local.EmailValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = json.Unmarshal(phoneNumberValidationBytes, &account.Authentication.Local.PhoneNumberValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
accounts = append(accounts, account)
|
|
}
|
|
return accounts, nil
|
|
}
|
|
|
|
func (psql PostgresqlStorage) GetAccountsByIds(accountids []string) ([]Account, error) {
|
|
var accounts []Account
|
|
accountIdsStr := "'" + strings.Join(accountids, "', '") + "'"
|
|
query := `
|
|
SELECT accounts.id, accounts.namespace, accounts.data, accounts.metadata,
|
|
account_auth.username, account_auth.password,
|
|
account_auth.email, account_auth.email_validation,
|
|
account_auth.phone_number, account_auth.phone_number_validation
|
|
FROM accounts
|
|
INNER JOIN account_auth ON accounts.id = account_auth.account_id
|
|
WHERE accounts.id IN (%s)
|
|
`
|
|
query = fmt.Sprintf(query, accountIdsStr)
|
|
rows, err := psql.DbConnection.Query(query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var account Account
|
|
var dataBytes []byte
|
|
var metadataBytes []byte
|
|
var emailValidationBytes []byte
|
|
var phoneNumberValidationBytes []byte
|
|
err := rows.Scan(
|
|
&account.ID,
|
|
&account.Namespace,
|
|
&dataBytes,
|
|
&metadataBytes,
|
|
&account.Authentication.Local.Username,
|
|
&account.Authentication.Local.Password,
|
|
&account.Authentication.Local.Email,
|
|
&emailValidationBytes,
|
|
&account.Authentication.Local.PhoneNumber,
|
|
&phoneNumberValidationBytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = json.Unmarshal(dataBytes, &account.Data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = json.Unmarshal(metadataBytes, &account.Metadata)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = json.Unmarshal(emailValidationBytes, &account.Authentication.Local.EmailValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = json.Unmarshal(phoneNumberValidationBytes, &account.Authentication.Local.PhoneNumberValidation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
accounts = append(accounts, account)
|
|
}
|
|
return accounts, nil
|
|
}
|
|
|
|
func (psql PostgresqlStorage) CreateAccount(account Account) error {
|
|
insertAccountStmt, err := psql.DbConnection.Prepare("INSERT INTO accounts (id, namespace, data, metadata)" +
|
|
" VALUES ($1, $2, $3, $4)")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
dataAccountJson, err := json.Marshal(account.Data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
metadataAccountJson, err := json.Marshal(account.Metadata)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = insertAccountStmt.Exec(account.ID, account.Namespace, dataAccountJson, metadataAccountJson)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
insertAccountAuthStmt, err := psql.DbConnection.Prepare("INSERT INTO account_auth (account_id, username," +
|
|
" password, email, email_validation,phone_number,phone_number_validation) " +
|
|
"values($1, $2, $3, $4, $5, $6, $7)")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
emailValidationJson, err := json.Marshal(account.Authentication.Local.EmailValidation)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
phoneValidationJson, err := json.Marshal(account.Authentication.Local.PhoneNumberValidation)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = insertAccountAuthStmt.Exec(account.ID,
|
|
account.Authentication.Local.Username,
|
|
account.Authentication.Local.Password,
|
|
account.Authentication.Local.Email,
|
|
emailValidationJson,
|
|
account.Authentication.Local.PhoneNumber,
|
|
phoneValidationJson)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (psql PostgresqlStorage) UpdateAccount(account Account) error {
|
|
updateAccountStmt, err := psql.DbConnection.Prepare("update accounts set namespace=$1, data=$2, " +
|
|
" metadata=$3 where id= $4")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
dataAccountJson, err := json.Marshal(account.Data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
metadataAccountJson, err := json.Marshal(account.Metadata)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = updateAccountStmt.Exec(account.Namespace, dataAccountJson, metadataAccountJson, account.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
updateAccountAuthStmt, err := psql.DbConnection.Prepare("update account_auth set username = $1," +
|
|
" password = $2," +
|
|
" email = $3, email_validation = $4 ," +
|
|
"phone_number = $5,phone_number_validation = $6 where account_id = $7")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
emailValidationJson, err := json.Marshal(account.Authentication.Local.EmailValidation)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
phoneValidationJson, err := json.Marshal(account.Authentication.Local.PhoneNumberValidation)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = updateAccountAuthStmt.Exec(account.Authentication.Local.Username,
|
|
account.Authentication.Local.Password,
|
|
account.Authentication.Local.Email,
|
|
emailValidationJson,
|
|
account.Authentication.Local.PhoneNumber,
|
|
phoneValidationJson, account.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|