Merge pull request #10 from kjannette/webhook-configs
webhook configs for users, changes to system
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
// Package database manages PostgreSQL connection pools.
|
|
||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -11,21 +10,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// maxConnIdleSeconds is the maximum idle time for a connection.
|
|
||||||
maxConnIdleSeconds = 30
|
maxConnIdleSeconds = 30
|
||||||
// maxConnLifetimeMinutes is the maximum lifetime for a connection.
|
|
||||||
maxConnLifetimeMinutes = 5
|
maxConnLifetimeMinutes = 5
|
||||||
// connectTimeoutSeconds is the timeout for initial connection.
|
|
||||||
connectTimeoutSeconds = 10
|
connectTimeoutSeconds = 10
|
||||||
// maxConns is the maximum number of connections in the pool.
|
|
||||||
maxConns = 20
|
maxConns = 20
|
||||||
// minConns is the minimum number of connections in the pool.
|
|
||||||
minConns = 2
|
minConns = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
var pool *pgxpool.Pool //nolint:gochecknoglobals
|
var pool *pgxpool.Pool //nolint:gochecknoglobals
|
||||||
|
|
||||||
// Connect establishes a PostgreSQL connection pool using the given DSN.
|
// establishPostgreSQL connection pool using the given DSN.
|
||||||
func Connect(dsn string) (*pgxpool.Pool, error) {
|
func Connect(dsn string) (*pgxpool.Pool, error) {
|
||||||
cfg, err := pgxpool.ParseConfig(dsn)
|
cfg, err := pgxpool.ParseConfig(dsn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -57,12 +56,10 @@ func Connect(dsn string) (*pgxpool.Pool, error) {
|
|||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pool returns the global connection pool.
|
|
||||||
func Pool() *pgxpool.Pool {
|
func Pool() *pgxpool.Pool {
|
||||||
return pool
|
return pool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the global connection pool.
|
|
||||||
func Close() {
|
func Close() {
|
||||||
if pool != nil {
|
if pool != nil {
|
||||||
pool.Close()
|
pool.Close()
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
// Package domain defines core domain types shared across the application.
|
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// Address represents a tracked Ethereum address.
|
|
||||||
type Address struct {
|
type Address struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
UserID string `json:"user_id"` //nolint:tagliatelle
|
UserID string `json:"user_id"` //nolint:tagliatelle
|
||||||
@@ -12,13 +10,10 @@ type Address struct {
|
|||||||
CreatedAt time.Time `json:"created_at"` //nolint:tagliatelle
|
CreatedAt time.Time `json:"created_at"` //nolint:tagliatelle
|
||||||
}
|
}
|
||||||
|
|
||||||
// AlertType identifies the kind of alert rule.
|
|
||||||
type AlertType string
|
type AlertType string
|
||||||
|
|
||||||
// String implements fmt.Stringer.
|
|
||||||
func (a AlertType) String() string { return string(a) }
|
func (a AlertType) String() string { return string(a) }
|
||||||
|
|
||||||
// Alert type constants define the supported alert triggers.
|
|
||||||
const (
|
const (
|
||||||
AlertIncomingTx AlertType = "incoming_tx"
|
AlertIncomingTx AlertType = "incoming_tx"
|
||||||
AlertOutgoingTx AlertType = "outgoing_tx"
|
AlertOutgoingTx AlertType = "outgoing_tx"
|
||||||
@@ -26,7 +21,6 @@ const (
|
|||||||
AlertBalanceBelow AlertType = "balance_below"
|
AlertBalanceBelow AlertType = "balance_below"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidAlertTypes lists all alert types accepted by the API.
|
|
||||||
var ValidAlertTypes = []AlertType{ //nolint:gochecknoglobals
|
var ValidAlertTypes = []AlertType{ //nolint:gochecknoglobals
|
||||||
AlertIncomingTx,
|
AlertIncomingTx,
|
||||||
AlertOutgoingTx,
|
AlertOutgoingTx,
|
||||||
@@ -62,7 +56,6 @@ func IsThresholdRequired(t AlertType) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// AlertRule represents a user-defined alert rule for an address.
|
|
||||||
type AlertRule struct {
|
type AlertRule struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
AddressID int `json:"address_id"` //nolint:tagliatelle
|
AddressID int `json:"address_id"` //nolint:tagliatelle
|
||||||
@@ -72,7 +65,6 @@ type AlertRule struct {
|
|||||||
CreatedAt time.Time `json:"created_at"` //nolint:tagliatelle
|
CreatedAt time.Time `json:"created_at"` //nolint:tagliatelle
|
||||||
}
|
}
|
||||||
|
|
||||||
// AlertEvent represents a fired alert event stored for history.
|
|
||||||
type AlertEvent struct {
|
type AlertEvent struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
AlertRuleID int `json:"alert_rule_id"` //nolint:tagliatelle
|
AlertRuleID int `json:"alert_rule_id"` //nolint:tagliatelle
|
||||||
@@ -82,7 +74,6 @@ type AlertEvent struct {
|
|||||||
Timestamp time.Time `json:"timestamp"`
|
Timestamp time.Time `json:"timestamp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddressCheckpoint tracks the last block checked for an address.
|
|
||||||
type AddressCheckpoint struct {
|
type AddressCheckpoint struct {
|
||||||
AddressID int `json:"address_id"` //nolint:tagliatelle
|
AddressID int `json:"address_id"` //nolint:tagliatelle
|
||||||
LastCheckedBlock int `json:"last_checked_block"` //nolint:tagliatelle
|
LastCheckedBlock int `json:"last_checked_block"` //nolint:tagliatelle
|
||||||
@@ -121,19 +112,16 @@ type NormalizedTx struct {
|
|||||||
BlockTimestamp int64 `json:"block_timestamp"` //nolint:tagliatelle
|
BlockTimestamp int64 `json:"block_timestamp"` //nolint:tagliatelle
|
||||||
}
|
}
|
||||||
|
|
||||||
// Direction indicates whether a transaction is incoming or outgoing.
|
|
||||||
type Direction string
|
type Direction string
|
||||||
|
|
||||||
// String implements fmt.Stringer.
|
// String implements fmt.Stringer.
|
||||||
func (d Direction) String() string { return string(d) }
|
func (d Direction) String() string { return string(d) }
|
||||||
|
|
||||||
// Direction constants indicate the flow of a transaction relative to a watched address.
|
|
||||||
const (
|
const (
|
||||||
DirectionIncoming Direction = "incoming"
|
DirectionIncoming Direction = "incoming"
|
||||||
DirectionOutgoing Direction = "outgoing"
|
DirectionOutgoing Direction = "outgoing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ObservedTx is a NormalizedTx enriched with address and direction context.
|
|
||||||
type ObservedTx struct {
|
type ObservedTx struct {
|
||||||
NormalizedTx
|
NormalizedTx
|
||||||
AddressID int `json:"address_id"` //nolint:tagliatelle
|
AddressID int `json:"address_id"` //nolint:tagliatelle
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// Package firebase provides Firebase authentication integration.
|
|
||||||
package firebase
|
package firebase
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -17,7 +16,6 @@ var ( //nolint:gochecknoglobals
|
|||||||
errInit error //nolint:gochecknoglobals
|
errInit error //nolint:gochecknoglobals
|
||||||
)
|
)
|
||||||
|
|
||||||
// Init initializes the Firebase app and auth client using the given project ID.
|
|
||||||
func Init(projectID string) error {
|
func Init(projectID string) error {
|
||||||
once.Do(func() {
|
once.Do(func() {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -48,7 +46,6 @@ func Init(projectID string) error {
|
|||||||
return errInit
|
return errInit
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auth returns the initialized Firebase auth client.
|
|
||||||
func Auth() *auth.Client {
|
func Auth() *auth.Client {
|
||||||
return authClient
|
return authClient
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,17 +15,14 @@ import (
|
|||||||
|
|
||||||
var ethAddressRe = regexp.MustCompile(`^0x[a-fA-F0-9]{40}$`)
|
var ethAddressRe = regexp.MustCompile(`^0x[a-fA-F0-9]{40}$`)
|
||||||
|
|
||||||
// AddressHandler handles HTTP requests for address management.
|
|
||||||
type AddressHandler struct {
|
type AddressHandler struct {
|
||||||
addresses *models.AddressModel
|
addresses *models.AddressModel
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAddressHandler creates a new AddressHandler.
|
|
||||||
func NewAddressHandler(addresses *models.AddressModel) *AddressHandler {
|
func NewAddressHandler(addresses *models.AddressModel) *AddressHandler {
|
||||||
return &AddressHandler{addresses: addresses}
|
return &AddressHandler{addresses: addresses}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create handles POST requests to add a new tracked address.
|
|
||||||
func (h *AddressHandler) Create(w http.ResponseWriter, r *http.Request) {
|
func (h *AddressHandler) Create(w http.ResponseWriter, r *http.Request) {
|
||||||
userID := middleware.GetUserID(r.Context())
|
userID := middleware.GetUserID(r.Context())
|
||||||
|
|
||||||
@@ -92,7 +89,7 @@ func (h *AddressHandler) List(w http.ResponseWriter, r *http.Request) {
|
|||||||
writeJSON(w, http.StatusOK, addresses)
|
writeJSON(w, http.StatusOK, addresses)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateLabel handles PATCH requests to update an address label.
|
// handles PATCH requests to update an address label.
|
||||||
func (h *AddressHandler) UpdateLabel(w http.ResponseWriter, r *http.Request) {
|
func (h *AddressHandler) UpdateLabel(w http.ResponseWriter, r *http.Request) {
|
||||||
userID := middleware.GetUserID(r.Context())
|
userID := middleware.GetUserID(r.Context())
|
||||||
addressID, ok := parseIntParam(r.PathValue("addressId"))
|
addressID, ok := parseIntParam(r.PathValue("addressId"))
|
||||||
|
|||||||
@@ -14,21 +14,17 @@ import (
|
|||||||
"github.com/kjannette/koin-ping/backend-go/internal/models"
|
"github.com/kjannette/koin-ping/backend-go/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// errThresholdFormat is returned when the threshold JSON cannot be decoded.
|
|
||||||
var errThresholdFormat = errors.New("unsupported threshold format")
|
var errThresholdFormat = errors.New("unsupported threshold format")
|
||||||
|
|
||||||
// AlertRuleHandler handles HTTP requests for alert rule management.
|
|
||||||
type AlertRuleHandler struct {
|
type AlertRuleHandler struct {
|
||||||
alertRules *models.AlertRuleModel
|
alertRules *models.AlertRuleModel
|
||||||
addresses *models.AddressModel
|
addresses *models.AddressModel
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAlertRuleHandler creates a new AlertRuleHandler.
|
|
||||||
func NewAlertRuleHandler(alertRules *models.AlertRuleModel, addresses *models.AddressModel) *AlertRuleHandler {
|
func NewAlertRuleHandler(alertRules *models.AlertRuleModel, addresses *models.AddressModel) *AlertRuleHandler {
|
||||||
return &AlertRuleHandler{alertRules: alertRules, addresses: addresses}
|
return &AlertRuleHandler{alertRules: alertRules, addresses: addresses}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create handles POST requests to create a new alert rule for an address.
|
|
||||||
func (h *AlertRuleHandler) Create(w http.ResponseWriter, r *http.Request) {
|
func (h *AlertRuleHandler) Create(w http.ResponseWriter, r *http.Request) {
|
||||||
userID := middleware.GetUserID(r.Context())
|
userID := middleware.GetUserID(r.Context())
|
||||||
addressID, ok := parseIntParam(r.PathValue("addressId"))
|
addressID, ok := parseIntParam(r.PathValue("addressId"))
|
||||||
|
|||||||
Reference in New Issue
Block a user