chore: remove cached
This commit is contained in:
@@ -1,19 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// AccessList defines IP-based or auth-based access control rules
|
||||
// that can be applied to proxy hosts.
|
||||
type AccessList struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
UUID string `json:"uuid" gorm:"uniqueIndex"`
|
||||
Name string `json:"name" gorm:"index"`
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"` // "allow", "deny", "basic_auth", "forward_auth"
|
||||
Rules string `json:"rules" gorm:"type:text"` // JSON array of rule definitions
|
||||
Enabled bool `json:"enabled" gorm:"default:true"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// CaddyConfig stores an audit trail of Caddy configuration changes.
|
||||
type CaddyConfig struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
ConfigHash string `json:"config_hash" gorm:"index"`
|
||||
AppliedAt time.Time `json:"applied_at"`
|
||||
Success bool `json:"success"`
|
||||
ErrorMsg string `json:"error_msg"`
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Domain struct {
|
||||
ID uint `json:"id" gorm:"primarykey"`
|
||||
UUID string `json:"uuid" gorm:"uniqueIndex;not null"`
|
||||
Name string `json:"name" gorm:"uniqueIndex;not null"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"`
|
||||
}
|
||||
|
||||
func (d *Domain) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
if d.UUID == "" {
|
||||
d.UUID = uuid.New().String()
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func TestDomain_BeforeCreate(t *testing.T) {
|
||||
db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
|
||||
assert.NoError(t, err)
|
||||
db.AutoMigrate(&Domain{})
|
||||
|
||||
// Case 1: UUID is empty, should be generated
|
||||
d1 := &Domain{Name: "example.com"}
|
||||
err = db.Create(d1).Error
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, d1.UUID)
|
||||
|
||||
// Case 2: UUID is provided, should be kept
|
||||
uuid := "123e4567-e89b-12d3-a456-426614174000"
|
||||
d2 := &Domain{Name: "test.com", UUID: uuid}
|
||||
err = db.Create(d2).Error
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, uuid, d2.UUID)
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// ImportSession tracks Caddyfile import operations with pending state
|
||||
// until user reviews and confirms via UI.
|
||||
type ImportSession struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
UUID string `json:"uuid" gorm:"uniqueIndex"`
|
||||
SourceFile string `json:"source_file"` // Path to original Caddyfile
|
||||
Status string `json:"status" gorm:"default:'pending'"` // "pending", "reviewing", "committed", "rejected", "failed"
|
||||
ParsedData string `json:"parsed_data" gorm:"type:text"` // JSON representation of detected hosts
|
||||
ConflictReport string `json:"conflict_report" gorm:"type:text"` // JSON array of conflicts
|
||||
UserResolutions string `json:"user_resolutions" gorm:"type:text"` // JSON map of conflict resolutions
|
||||
ErrorMsg string `json:"error_msg"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
CommittedAt *time.Time `json:"committed_at,omitempty"`
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Location represents a custom path-based proxy configuration within a ProxyHost.
|
||||
type Location struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
UUID string `json:"uuid" gorm:"uniqueIndex;not null"`
|
||||
ProxyHostID uint `json:"proxy_host_id" gorm:"not null;index"`
|
||||
Path string `json:"path" gorm:"not null"` // e.g., /api, /admin
|
||||
ForwardScheme string `json:"forward_scheme" gorm:"default:http"`
|
||||
ForwardHost string `json:"forward_host" gorm:"not null"`
|
||||
ForwardPort int `json:"forward_port" gorm:"not null"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package models
|
||||
|
||||
// CaddyAccessLog represents a structured log entry from Caddy's JSON access logs.
|
||||
type CaddyAccessLog struct {
|
||||
Level string `json:"level"`
|
||||
Ts float64 `json:"ts"`
|
||||
Logger string `json:"logger"`
|
||||
Msg string `json:"msg"`
|
||||
Request struct {
|
||||
RemoteIP string `json:"remote_ip"`
|
||||
RemotePort string `json:"remote_port"`
|
||||
ClientIP string `json:"client_ip"`
|
||||
Proto string `json:"proto"`
|
||||
Method string `json:"method"`
|
||||
Host string `json:"host"`
|
||||
URI string `json:"uri"`
|
||||
Headers map[string][]string `json:"headers"`
|
||||
TLS struct {
|
||||
Resumed bool `json:"resumed"`
|
||||
Version int `json:"version"`
|
||||
CipherSuite int `json:"cipher_suite"`
|
||||
Proto string `json:"proto"`
|
||||
ServerName string `json:"server_name"`
|
||||
} `json:"tls"`
|
||||
} `json:"request"`
|
||||
BytesRead int `json:"bytes_read"`
|
||||
UserID string `json:"user_id"`
|
||||
Duration float64 `json:"duration"`
|
||||
Size int `json:"size"`
|
||||
Status int `json:"status"`
|
||||
RespHeaders map[string][]string `json:"resp_headers"`
|
||||
}
|
||||
|
||||
// LogFilter defines criteria for filtering logs.
|
||||
type LogFilter struct {
|
||||
Search string `form:"search"`
|
||||
Host string `form:"host"`
|
||||
Status string `form:"status"` // e.g., "200", "4xx", "5xx"
|
||||
Level string `form:"level"`
|
||||
Limit int `form:"limit"`
|
||||
Offset int `form:"offset"`
|
||||
Sort string `form:"sort"`
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type NotificationType string
|
||||
|
||||
const (
|
||||
NotificationTypeInfo NotificationType = "info"
|
||||
NotificationTypeSuccess NotificationType = "success"
|
||||
NotificationTypeWarning NotificationType = "warning"
|
||||
NotificationTypeError NotificationType = "error"
|
||||
)
|
||||
|
||||
type Notification struct {
|
||||
ID string `gorm:"primaryKey" json:"id"`
|
||||
Type NotificationType `json:"type"`
|
||||
Title string `json:"title"`
|
||||
Message string `json:"message"`
|
||||
Read bool `json:"read"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
func (n *Notification) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
if n.ID == "" {
|
||||
n.ID = uuid.New().String()
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type NotificationProvider struct {
|
||||
ID string `gorm:"primaryKey" json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // discord, slack, gotify, telegram, generic, webhook
|
||||
URL string `json:"url"` // The shoutrrr URL or webhook URL
|
||||
Config string `json:"config"` // JSON payload template for custom webhooks
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// Notification Preferences
|
||||
NotifyProxyHosts bool `json:"notify_proxy_hosts" gorm:"default:true"`
|
||||
NotifyRemoteServers bool `json:"notify_remote_servers" gorm:"default:true"`
|
||||
NotifyDomains bool `json:"notify_domains" gorm:"default:true"`
|
||||
NotifyCerts bool `json:"notify_certs" gorm:"default:true"`
|
||||
NotifyUptime bool `json:"notify_uptime" gorm:"default:true"`
|
||||
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (n *NotificationProvider) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
if n.ID == "" {
|
||||
n.ID = uuid.New().String()
|
||||
}
|
||||
// Set defaults if not explicitly set (though gorm default tag handles DB side)
|
||||
// We can't easily distinguish between false and unset for bools here without pointers,
|
||||
// but for new creations via API, we can assume the frontend sends what it wants.
|
||||
// If we wanted to force defaults in Go:
|
||||
// n.NotifyProxyHosts = true ...
|
||||
return
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package models_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/Wikid82/CaddyProxyManagerPlus/backend/internal/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func TestNotificationProvider_BeforeCreate(t *testing.T) {
|
||||
db, err := gorm.Open(sqlite.Open("file::memory:"), &gorm.Config{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.AutoMigrate(&models.NotificationProvider{}))
|
||||
|
||||
provider := models.NotificationProvider{
|
||||
Name: "Test",
|
||||
}
|
||||
err = db.Create(&provider).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotEmpty(t, provider.ID)
|
||||
// Check defaults if any (currently none enforced in BeforeCreate other than ID)
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func TestNotification_BeforeCreate(t *testing.T) {
|
||||
db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
|
||||
assert.NoError(t, err)
|
||||
db.AutoMigrate(&Notification{})
|
||||
|
||||
// Case 1: ID is empty, should be generated
|
||||
n1 := &Notification{Title: "Test", Message: "Test Message"}
|
||||
err = db.Create(n1).Error
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, n1.ID)
|
||||
|
||||
// Case 2: ID is provided, should be kept
|
||||
id := "123e4567-e89b-12d3-a456-426614174000"
|
||||
n2 := &Notification{ID: id, Title: "Test 2", Message: "Test Message 2"}
|
||||
err = db.Create(n2).Error
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, id, n2.ID)
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// ProxyHost represents a reverse proxy configuration.
|
||||
type ProxyHost struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
UUID string `json:"uuid" gorm:"uniqueIndex;not null"`
|
||||
Name string `json:"name"`
|
||||
DomainNames string `json:"domain_names" gorm:"not null"` // Comma-separated list
|
||||
ForwardScheme string `json:"forward_scheme" gorm:"default:http"`
|
||||
ForwardHost string `json:"forward_host" gorm:"not null"`
|
||||
ForwardPort int `json:"forward_port" gorm:"not null"`
|
||||
SSLForced bool `json:"ssl_forced" gorm:"default:false"`
|
||||
HTTP2Support bool `json:"http2_support" gorm:"default:true"`
|
||||
HSTSEnabled bool `json:"hsts_enabled" gorm:"default:false"`
|
||||
HSTSSubdomains bool `json:"hsts_subdomains" gorm:"default:false"`
|
||||
BlockExploits bool `json:"block_exploits" gorm:"default:true"`
|
||||
WebsocketSupport bool `json:"websocket_support" gorm:"default:false"`
|
||||
Enabled bool `json:"enabled" gorm:"default:true"`
|
||||
CertificateID *uint `json:"certificate_id"`
|
||||
Certificate *SSLCertificate `json:"certificate" gorm:"foreignKey:CertificateID"`
|
||||
Locations []Location `json:"locations" gorm:"foreignKey:ProxyHostID;constraint:OnDelete:CASCADE"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// RemoteServer represents a known backend server that can be selected
|
||||
// when creating proxy hosts, eliminating manual IP/port entry.
|
||||
type RemoteServer struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
UUID string `json:"uuid" gorm:"uniqueIndex"`
|
||||
Name string `json:"name" gorm:"index"`
|
||||
Provider string `json:"provider"` // e.g., "docker", "vm", "cloud", "manual"
|
||||
Host string `json:"host"` // IP address or hostname
|
||||
Port int `json:"port"`
|
||||
Scheme string `json:"scheme"` // http/https
|
||||
Tags string `json:"tags"` // comma-separated tags for filtering
|
||||
Description string `json:"description"`
|
||||
Enabled bool `json:"enabled" gorm:"default:true"`
|
||||
LastChecked *time.Time `json:"last_checked,omitempty"`
|
||||
Reachable bool `json:"reachable" gorm:"default:false"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Setting stores global application configuration as key-value pairs.
|
||||
// Used for system-wide preferences, feature flags, and runtime config.
|
||||
type Setting struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
Key string `json:"key" gorm:"uniqueIndex"`
|
||||
Value string `json:"value" gorm:"type:text"`
|
||||
Type string `json:"type"` // "string", "int", "bool", "json"
|
||||
Category string `json:"category"` // "general", "security", "caddy", "smtp", etc.
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// SSLCertificate represents TLS certificates managed by CPM+.
|
||||
// Can be Let's Encrypt auto-generated or custom uploaded certs.
|
||||
type SSLCertificate struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
UUID string `json:"uuid" gorm:"uniqueIndex"`
|
||||
Name string `json:"name"`
|
||||
Provider string `json:"provider"` // "letsencrypt", "custom", "self-signed"
|
||||
Domains string `json:"domains"` // comma-separated list of domains
|
||||
Certificate string `json:"certificate" gorm:"type:text"` // PEM-encoded certificate
|
||||
PrivateKey string `json:"private_key" gorm:"type:text"` // PEM-encoded private key
|
||||
ExpiresAt *time.Time `json:"expires_at,omitempty"`
|
||||
AutoRenew bool `json:"auto_renew" gorm:"default:false"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type UptimeMonitor struct {
|
||||
ID string `gorm:"primaryKey" json:"id"`
|
||||
ProxyHostID *uint `json:"proxy_host_id"` // Optional link to proxy host
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"` // http, tcp, ping
|
||||
URL string `json:"url"`
|
||||
Interval int `json:"interval"` // seconds
|
||||
Enabled bool `json:"enabled"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// Current Status (Cached)
|
||||
Status string `json:"status"` // up, down, maintenance, pending
|
||||
LastCheck time.Time `json:"last_check"`
|
||||
Latency int64 `json:"latency"` // ms
|
||||
}
|
||||
|
||||
type UptimeHeartbeat struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
MonitorID string `json:"monitor_id" gorm:"index"`
|
||||
Status string `json:"status"` // up, down
|
||||
Latency int64 `json:"latency"`
|
||||
Message string `json:"message"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"index"`
|
||||
}
|
||||
|
||||
func (m *UptimeMonitor) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
if m.ID == "" {
|
||||
m.ID = uuid.New().String()
|
||||
}
|
||||
if m.Status == "" {
|
||||
m.Status = "pending"
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package models_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/Wikid82/CaddyProxyManagerPlus/backend/internal/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func TestUptimeMonitor_BeforeCreate(t *testing.T) {
|
||||
db, err := gorm.Open(sqlite.Open("file::memory:"), &gorm.Config{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.AutoMigrate(&models.UptimeMonitor{}))
|
||||
|
||||
monitor := models.UptimeMonitor{
|
||||
Name: "Test",
|
||||
}
|
||||
err = db.Create(&monitor).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotEmpty(t, monitor.ID)
|
||||
assert.Equal(t, "pending", monitor.Status)
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// User represents authenticated users with role-based access control.
|
||||
// Supports local auth, SSO integration planned for later phases.
|
||||
type User struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
UUID string `json:"uuid" gorm:"uniqueIndex"`
|
||||
Email string `json:"email" gorm:"uniqueIndex"`
|
||||
APIKey string `json:"api_key" gorm:"uniqueIndex"` // For external API access
|
||||
PasswordHash string `json:"-"` // Never serialize password hash
|
||||
Name string `json:"name"`
|
||||
Role string `json:"role" gorm:"default:'user'"` // "admin", "user", "viewer"
|
||||
Enabled bool `json:"enabled" gorm:"default:true"`
|
||||
FailedLoginAttempts int `json:"-" gorm:"default:0"`
|
||||
LockedUntil *time.Time `json:"-"`
|
||||
LastLogin *time.Time `json:"last_login,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// SetPassword hashes and sets the user's password.
|
||||
func (u *User) SetPassword(password string) error {
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.PasswordHash = string(hash)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckPassword compares the provided password with the stored hash.
|
||||
func (u *User) CheckPassword(password string) bool {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(u.PasswordHash), []byte(password))
|
||||
return err == nil
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUser_SetPassword(t *testing.T) {
|
||||
u := &User{}
|
||||
err := u.SetPassword("password123")
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, u.PasswordHash)
|
||||
assert.NotEqual(t, "password123", u.PasswordHash)
|
||||
}
|
||||
|
||||
func TestUser_CheckPassword(t *testing.T) {
|
||||
u := &User{}
|
||||
_ = u.SetPassword("password123")
|
||||
|
||||
assert.True(t, u.CheckPassword("password123"))
|
||||
assert.False(t, u.CheckPassword("wrongpassword"))
|
||||
}
|
||||
Reference in New Issue
Block a user