initital commit
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
// License represents a license record in the database.
|
||||
type License struct {
|
||||
ID string
|
||||
Key string
|
||||
CustomerName string
|
||||
CustomerEmail string
|
||||
ProductName string
|
||||
Type string // expiry | usage
|
||||
ExpiresAt *time.Time
|
||||
MaxUses *int
|
||||
UsedCount int
|
||||
MachineID string
|
||||
Active bool
|
||||
CreatedAt time.Time
|
||||
SearchText string // pre-built lowercase search string for the UI
|
||||
}
|
||||
|
||||
// Activation records each machine that activated a license.
|
||||
type Activation struct {
|
||||
ID string
|
||||
LicenseID string
|
||||
MachineID string
|
||||
Hostname string
|
||||
OS string
|
||||
ActivatedAt time.Time
|
||||
}
|
||||
|
||||
// DB wraps the SQLite connection with helper methods.
|
||||
type DB struct {
|
||||
conn *sql.DB
|
||||
}
|
||||
|
||||
// Open opens (or creates) the SQLite database at path.
|
||||
func Open(path string) (*DB, error) {
|
||||
conn, err := sql.Open("sqlite", path+"?_journal=WAL&_timeout=5000")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db := &DB{conn: conn}
|
||||
return db, db.migrate()
|
||||
}
|
||||
|
||||
func (db *DB) migrate() error {
|
||||
_, err := db.conn.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS licenses (
|
||||
id TEXT PRIMARY KEY,
|
||||
key TEXT UNIQUE NOT NULL,
|
||||
customer_name TEXT NOT NULL,
|
||||
customer_email TEXT NOT NULL,
|
||||
product_name TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
expires_at DATETIME,
|
||||
max_uses INTEGER,
|
||||
used_count INTEGER NOT NULL DEFAULT 0,
|
||||
machine_id TEXT,
|
||||
active INTEGER NOT NULL DEFAULT 1,
|
||||
created_at DATETIME NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS activations (
|
||||
id TEXT PRIMARY KEY,
|
||||
license_id TEXT NOT NULL REFERENCES licenses(id),
|
||||
machine_id TEXT NOT NULL,
|
||||
hostname TEXT,
|
||||
os TEXT,
|
||||
activated_at DATETIME NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id TEXT PRIMARY KEY,
|
||||
email TEXT UNIQUE NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
created_at DATETIME NOT NULL
|
||||
);
|
||||
`)
|
||||
return err
|
||||
}
|
||||
|
||||
// --- License CRUD ---
|
||||
|
||||
func (db *DB) CreateLicense(l *License) error {
|
||||
_, err := db.conn.Exec(`
|
||||
INSERT INTO licenses (id, key, customer_name, customer_email, product_name,
|
||||
type, expires_at, max_uses, machine_id, active, created_at)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?)`,
|
||||
l.ID, l.Key, l.CustomerName, l.CustomerEmail, l.ProductName,
|
||||
l.Type, l.ExpiresAt, l.MaxUses, l.MachineID, l.Active, l.CreatedAt,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) ListLicenses() ([]License, error) {
|
||||
rows, err := db.conn.Query(`
|
||||
SELECT id, key, customer_name, customer_email, product_name,
|
||||
type, expires_at, max_uses, used_count, machine_id, active, created_at
|
||||
FROM licenses ORDER BY created_at DESC`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var licenses []License
|
||||
for rows.Next() {
|
||||
var l License
|
||||
if err := rows.Scan(&l.ID, &l.Key, &l.CustomerName, &l.CustomerEmail,
|
||||
&l.ProductName, &l.Type, &l.ExpiresAt, &l.MaxUses,
|
||||
&l.UsedCount, &l.MachineID, &l.Active, &l.CreatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l.SearchText = strings.ToLower(fmt.Sprintf("%s %s %s %s %s",
|
||||
l.Key, l.CustomerName, l.CustomerEmail, l.ProductName, l.MachineID))
|
||||
licenses = append(licenses, l)
|
||||
}
|
||||
return licenses, nil
|
||||
}
|
||||
|
||||
func (db *DB) GetLicenseByKey(key string) (*License, error) {
|
||||
var l License
|
||||
err := db.conn.QueryRow(`
|
||||
SELECT id, key, customer_name, customer_email, product_name,
|
||||
type, expires_at, max_uses, used_count, machine_id, active, created_at
|
||||
FROM licenses WHERE key = ?`, key).
|
||||
Scan(&l.ID, &l.Key, &l.CustomerName, &l.CustomerEmail,
|
||||
&l.ProductName, &l.Type, &l.ExpiresAt, &l.MaxUses,
|
||||
&l.UsedCount, &l.MachineID, &l.Active, &l.CreatedAt)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
return &l, err
|
||||
}
|
||||
|
||||
func (db *DB) RevokeLicense(id string) error {
|
||||
_, err := db.conn.Exec(`UPDATE licenses SET active = 0 WHERE id = ?`, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) ActivateLicense(id string) error {
|
||||
_, err := db.conn.Exec(`UPDATE licenses SET active = 1 WHERE id = ?`, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) IncrementUsage(id string) error {
|
||||
_, err := db.conn.Exec(`UPDATE licenses SET used_count = used_count + 1 WHERE id = ?`, id)
|
||||
return err
|
||||
}
|
||||
|
||||
// --- Activations ---
|
||||
|
||||
func (db *DB) RecordActivation(a *Activation) error {
|
||||
_, err := db.conn.Exec(`
|
||||
INSERT OR REPLACE INTO activations (id, license_id, machine_id, hostname, os, activated_at)
|
||||
VALUES (?,?,?,?,?,?)`,
|
||||
a.ID, a.LicenseID, a.MachineID, a.Hostname, a.OS, a.ActivatedAt,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) ListActivations(licenseID string) ([]Activation, error) {
|
||||
rows, err := db.conn.Query(`
|
||||
SELECT id, license_id, machine_id, hostname, os, activated_at
|
||||
FROM activations WHERE license_id = ? ORDER BY activated_at DESC`, licenseID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var acts []Activation
|
||||
for rows.Next() {
|
||||
var a Activation
|
||||
rows.Scan(&a.ID, &a.LicenseID, &a.MachineID, &a.Hostname, &a.OS, &a.ActivatedAt)
|
||||
acts = append(acts, a)
|
||||
}
|
||||
return acts, nil
|
||||
}
|
||||
|
||||
// --- Users ---
|
||||
|
||||
func (db *DB) CreateUser(id, email, hash string) error {
|
||||
_, err := db.conn.Exec(`
|
||||
INSERT INTO users (id, email, password_hash, created_at) VALUES (?,?,?,?)`,
|
||||
id, email, hash, time.Now())
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) GetUserByEmail(email string) (id, hash string, err error) {
|
||||
err = db.conn.QueryRow(
|
||||
`SELECT id, password_hash FROM users WHERE email = ?`, email).
|
||||
Scan(&id, &hash)
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) UserCount() int {
|
||||
var n int
|
||||
db.conn.QueryRow(`SELECT COUNT(*) FROM users`).Scan(&n)
|
||||
return n
|
||||
}
|
||||
Reference in New Issue
Block a user