first commit
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
DatabaseURL string
|
||||
}
|
||||
|
||||
func Load() (*Config, error) {
|
||||
url := os.Getenv("DATABASE_URL")
|
||||
if url == "" {
|
||||
return nil, fmt.Errorf("DATABASE_URL is required")
|
||||
}
|
||||
return &Config{DatabaseURL: url}, nil
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
_ "github.com/golang-migrate/migrate/v4/database/postgres"
|
||||
_ "github.com/golang-migrate/migrate/v4/source/file"
|
||||
)
|
||||
|
||||
func RunMigrations(databaseURL, migrationsPath string) error {
|
||||
m, err := migrate.New(
|
||||
fmt.Sprintf("file://%s", migrationsPath),
|
||||
databaseURL,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create migrator: %w", err)
|
||||
}
|
||||
defer m.Close()
|
||||
|
||||
if err := m.Up(); err != nil && !errors.Is(err, migrate.ErrNoChange) {
|
||||
return fmt.Errorf("migrate up: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func RollbackMigrations(databaseURL, migrationsPath string) error {
|
||||
m, err := migrate.New(
|
||||
fmt.Sprintf("file://%s", migrationsPath),
|
||||
databaseURL,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create migrator: %w", err)
|
||||
}
|
||||
defer m.Close()
|
||||
|
||||
if err := m.Down(); err != nil && !errors.Is(err, migrate.ErrNoChange) {
|
||||
return fmt.Errorf("migrate down: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
func NewPool(ctx context.Context, databaseURL string) (*pgxpool.Pool, error) {
|
||||
cfg, err := pgxpool.ParseConfig(databaseURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse database url: %w", err)
|
||||
}
|
||||
|
||||
cfg.MaxConns = 20
|
||||
cfg.MinConns = 2
|
||||
cfg.MaxConnLifetime = time.Hour
|
||||
cfg.MaxConnIdleTime = 30 * time.Minute
|
||||
cfg.HealthCheckPeriod = time.Minute
|
||||
|
||||
pool, err := pgxpool.NewWithConfig(ctx, cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create pool: %w", err)
|
||||
}
|
||||
|
||||
if err := pool.Ping(ctx); err != nil {
|
||||
pool.Close()
|
||||
return nil, fmt.Errorf("ping database: %w", err)
|
||||
}
|
||||
|
||||
return pool, nil
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type UserStatus string
|
||||
|
||||
const (
|
||||
UserStatusActive UserStatus = "active"
|
||||
UserStatusSuspended UserStatus = "suspended"
|
||||
UserStatusPending UserStatus = "pending"
|
||||
)
|
||||
|
||||
type UserRole string
|
||||
|
||||
const (
|
||||
RoleSuperAdmin UserRole = "superadmin"
|
||||
RoleAdmin UserRole = "admin"
|
||||
RoleReseller UserRole = "reseller"
|
||||
RoleUser UserRole = "user"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID int64 `json:"id"`
|
||||
UUID uuid.UUID `json:"uuid"`
|
||||
Email string `json:"email"`
|
||||
Username string `json:"username"`
|
||||
PasswordHash string `json:"-"`
|
||||
Role UserRole `json:"role"`
|
||||
Status UserStatus `json:"status"`
|
||||
Locale string `json:"locale"`
|
||||
Timezone string `json:"timezone"`
|
||||
LastLoginAt *time.Time `json:"last_login_at,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ServerStatus string
|
||||
|
||||
const (
|
||||
ServerOnline ServerStatus = "online"
|
||||
ServerOffline ServerStatus = "offline"
|
||||
ServerMaintenance ServerStatus = "maintenance"
|
||||
ServerProvisioning ServerStatus = "provisioning"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
ID int64 `json:"id"`
|
||||
UUID uuid.UUID `json:"uuid"`
|
||||
Name string `json:"name"`
|
||||
Hostname string `json:"hostname"`
|
||||
IPAddress string `json:"ip_address"`
|
||||
SSHPort int `json:"ssh_port"`
|
||||
Status ServerStatus `json:"status"`
|
||||
AgentVersion *string `json:"agent_version,omitempty"`
|
||||
OSInfo map[string]any `json:"os_info"`
|
||||
Resources map[string]any `json:"resources"`
|
||||
Settings map[string]any `json:"settings"`
|
||||
LastSeenAt *time.Time `json:"last_seen_at,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type SiteStatus string
|
||||
|
||||
const (
|
||||
SiteActive SiteStatus = "active"
|
||||
SiteSuspended SiteStatus = "suspended"
|
||||
SiteCreating SiteStatus = "creating"
|
||||
SiteDeleting SiteStatus = "deleting"
|
||||
SiteError SiteStatus = "error"
|
||||
)
|
||||
|
||||
type Site struct {
|
||||
ID int64 `json:"id"`
|
||||
UUID uuid.UUID `json:"uuid"`
|
||||
ServerID int64 `json:"server_id"`
|
||||
OwnerID int64 `json:"owner_id"`
|
||||
Name string `json:"name"`
|
||||
DocumentRoot string `json:"document_root"`
|
||||
PHPVersion *string `json:"php_version,omitempty"`
|
||||
Status SiteStatus `json:"status"`
|
||||
Settings map[string]any `json:"settings"`
|
||||
DiskQuotaMB *int `json:"disk_quota_mb,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type Domain struct {
|
||||
ID int64 `json:"id"`
|
||||
SiteID int64 `json:"site_id"`
|
||||
Domain string `json:"domain"`
|
||||
IsPrimary bool `json:"is_primary"`
|
||||
SSLEnabled bool `json:"ssl_enabled"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type DBEngine string
|
||||
|
||||
const (
|
||||
EngineMySQL DBEngine = "mysql"
|
||||
EnginePostgreSQL DBEngine = "postgresql"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
ID int64 `json:"id"`
|
||||
UUID uuid.UUID `json:"uuid"`
|
||||
SiteID int64 `json:"site_id"`
|
||||
ServerID int64 `json:"server_id"`
|
||||
Name string `json:"name"`
|
||||
Engine DBEngine `json:"engine"`
|
||||
Charset string `json:"charset"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type JobStatus string
|
||||
|
||||
const (
|
||||
JobPending JobStatus = "pending"
|
||||
JobRunning JobStatus = "running"
|
||||
JobCompleted JobStatus = "completed"
|
||||
JobFailed JobStatus = "failed"
|
||||
JobCancelled JobStatus = "cancelled"
|
||||
)
|
||||
|
||||
type Job struct {
|
||||
ID int64 `json:"id"`
|
||||
UUID uuid.UUID `json:"uuid"`
|
||||
ServerID *int64 `json:"server_id,omitempty"`
|
||||
SiteID *int64 `json:"site_id,omitempty"`
|
||||
UserID *int64 `json:"user_id,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Payload map[string]any `json:"payload"`
|
||||
Status JobStatus `json:"status"`
|
||||
Result map[string]any `json:"result,omitempty"`
|
||||
ErrorMessage *string `json:"error_message,omitempty"`
|
||||
Attempts int `json:"attempts"`
|
||||
MaxAttempts int `json:"max_attempts"`
|
||||
ScheduledAt time.Time `json:"scheduled_at"`
|
||||
StartedAt *time.Time `json:"started_at,omitempty"`
|
||||
CompletedAt *time.Time `json:"completed_at,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
Reference in New Issue
Block a user