feat: initialize database schema and implement core Radius entities, EF context, and account enforcement service.
Build and Push Docker Image to Gitea Container Registry / build-and-push (push) Successful in 1m12s
Build and Push Docker Image to Gitea Container Registry / build-and-push (push) Successful in 1m12s
This commit is contained in:
@@ -131,3 +131,58 @@ INSERT INTO system_settings (key, value) VALUES ('default_data_limit', '500') ON
|
||||
|
||||
-- System settings initialized on startup
|
||||
-- Admin user is created by administrator during first startup via the web interface
|
||||
|
||||
-- Dedicated table for robust, per-user data tracking that survives AP counter resets
|
||||
CREATE TABLE IF NOT EXISTS guest_data_usage (
|
||||
username VARCHAR(64) PRIMARY KEY,
|
||||
total_input_octets BIGINT NOT NULL DEFAULT 0,
|
||||
total_output_octets BIGINT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
-- Trigger function to safely accumulate data usage from radacct
|
||||
CREATE OR REPLACE FUNCTION update_guest_data_usage()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
delta_input BIGINT := 0;
|
||||
delta_output BIGINT := 0;
|
||||
BEGIN
|
||||
-- Handle INSERT (new session)
|
||||
IF (TG_OP = 'INSERT') THEN
|
||||
delta_input := COALESCE(NEW.acctinputoctets, 0);
|
||||
delta_output := COALESCE(NEW.acctoutputoctets, 0);
|
||||
-- Handle UPDATE (interim updates)
|
||||
ELSIF (TG_OP = 'UPDATE') THEN
|
||||
-- Only add if the new value is greater than the old value (protects against counter resets)
|
||||
IF (COALESCE(NEW.acctinputoctets, 0) > COALESCE(OLD.acctinputoctets, 0)) THEN
|
||||
delta_input := NEW.acctinputoctets - COALESCE(OLD.acctinputoctets, 0);
|
||||
ELSIF (COALESCE(NEW.acctinputoctets, 0) < COALESCE(OLD.acctinputoctets, 0)) THEN
|
||||
-- Counter reset mid-session! Just add the new value as the delta.
|
||||
delta_input := COALESCE(NEW.acctinputoctets, 0);
|
||||
END IF;
|
||||
|
||||
IF (COALESCE(NEW.acctoutputoctets, 0) > COALESCE(OLD.acctoutputoctets, 0)) THEN
|
||||
delta_output := NEW.acctoutputoctets - COALESCE(OLD.acctoutputoctets, 0);
|
||||
ELSIF (COALESCE(NEW.acctoutputoctets, 0) < COALESCE(OLD.acctoutputoctets, 0)) THEN
|
||||
-- Counter reset mid-session!
|
||||
delta_output := COALESCE(NEW.acctoutputoctets, 0);
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- Upsert the calculated deltas into the usage table per-user
|
||||
IF (delta_input > 0 OR delta_output > 0) THEN
|
||||
INSERT INTO guest_data_usage (username, total_input_octets, total_output_octets)
|
||||
VALUES (NEW.username, delta_input, delta_output)
|
||||
ON CONFLICT (username) DO UPDATE
|
||||
SET total_input_octets = guest_data_usage.total_input_octets + EXCLUDED.total_input_octets,
|
||||
total_output_octets = guest_data_usage.total_output_octets + EXCLUDED.total_output_octets;
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Attach trigger to radacct table
|
||||
DROP TRIGGER IF EXISTS trg_update_guest_data_usage ON radacct;
|
||||
CREATE TRIGGER trg_update_guest_data_usage
|
||||
AFTER INSERT OR UPDATE OF acctinputoctets, acctoutputoctets ON radacct
|
||||
FOR EACH ROW EXECUTE FUNCTION update_guest_data_usage();
|
||||
|
||||
Reference in New Issue
Block a user