-- Add scanner lock functionality to events table -- This migration adds support for locking scanner devices to scan-only mode -- Add scanner lock fields to events table ALTER TABLE events ADD COLUMN scanner_lock_enabled BOOLEAN DEFAULT FALSE; ALTER TABLE events ADD COLUMN scanner_pin_hash TEXT; ALTER TABLE events ADD COLUMN scanner_lock_created_at TIMESTAMP WITH TIME ZONE; ALTER TABLE events ADD COLUMN scanner_lock_created_by UUID REFERENCES users(id); -- Create scanner_unlock_attempts table for audit logging CREATE TABLE scanner_unlock_attempts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), event_id UUID NOT NULL REFERENCES events(id) ON DELETE CASCADE, attempted_by UUID REFERENCES users(id), attempt_result TEXT NOT NULL CHECK (attempt_result IN ('SUCCESS', 'FAILED', 'INVALID_PIN')), ip_address TEXT, user_agent TEXT, device_info TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Add indexes for performance CREATE INDEX idx_scanner_unlock_attempts_event_id ON scanner_unlock_attempts(event_id); CREATE INDEX idx_scanner_unlock_attempts_created_at ON scanner_unlock_attempts(created_at); CREATE INDEX idx_scanner_unlock_attempts_result ON scanner_unlock_attempts(attempt_result); -- Add RLS policies for scanner_unlock_attempts ALTER TABLE scanner_unlock_attempts ENABLE ROW LEVEL SECURITY; -- Policies for scanner_unlock_attempts CREATE POLICY "Users can view scanner unlock attempts in their organization" ON scanner_unlock_attempts FOR SELECT USING ( EXISTS ( SELECT 1 FROM users WHERE users.id = auth.uid() AND users.organization_id = ( SELECT organization_id FROM events WHERE events.id = scanner_unlock_attempts.event_id ) ) ); CREATE POLICY "Users can insert scanner unlock attempts in their organization" ON scanner_unlock_attempts FOR INSERT WITH CHECK ( EXISTS ( SELECT 1 FROM users WHERE users.id = auth.uid() AND users.organization_id = ( SELECT organization_id FROM events WHERE events.id = scanner_unlock_attempts.event_id ) ) ); -- Admin override policies (for users with admin privileges) CREATE POLICY "Admin can view all scanner unlock attempts" ON scanner_unlock_attempts FOR SELECT USING ( EXISTS ( SELECT 1 FROM users WHERE users.id = auth.uid() AND users.organization_id IS NULL ) ); CREATE POLICY "Admin can manage all scanner unlock attempts" ON scanner_unlock_attempts FOR ALL USING ( EXISTS ( SELECT 1 FROM users WHERE users.id = auth.uid() AND users.organization_id IS NULL ) ); -- Create function to clean up scanner lock when event ends CREATE OR REPLACE FUNCTION cleanup_expired_scanner_locks() RETURNS void AS $$ BEGIN -- Disable scanner locks for events that ended more than 24 hours ago UPDATE events SET scanner_lock_enabled = FALSE, scanner_pin_hash = NULL, scanner_lock_created_at = NULL, scanner_lock_created_by = NULL WHERE scanner_lock_enabled = TRUE AND start_time < NOW() - INTERVAL '24 hours'; END; $$ LANGUAGE plpgsql; -- Create a function to be called when setting up scanner lock CREATE OR REPLACE FUNCTION setup_scanner_lock( p_event_id UUID, p_pin_hash TEXT ) RETURNS BOOLEAN AS $$ BEGIN -- Update the event with scanner lock settings UPDATE events SET scanner_lock_enabled = TRUE, scanner_pin_hash = p_pin_hash, scanner_lock_created_at = NOW(), scanner_lock_created_by = auth.uid() WHERE id = p_event_id; -- Return true if update was successful RETURN FOUND; END; $$ LANGUAGE plpgsql; -- Create a function to verify scanner PIN CREATE OR REPLACE FUNCTION verify_scanner_pin( p_event_id UUID, p_pin_hash TEXT ) RETURNS BOOLEAN AS $$ DECLARE stored_hash TEXT; BEGIN -- Get the stored PIN hash SELECT scanner_pin_hash INTO stored_hash FROM events WHERE id = p_event_id AND scanner_lock_enabled = TRUE; -- Return true if hashes match RETURN stored_hash = p_pin_hash; END; $$ LANGUAGE plpgsql; -- Create a function to disable scanner lock CREATE OR REPLACE FUNCTION disable_scanner_lock( p_event_id UUID ) RETURNS BOOLEAN AS $$ BEGIN -- Update the event to disable scanner lock UPDATE events SET scanner_lock_enabled = FALSE, scanner_pin_hash = NULL, scanner_lock_created_at = NULL, scanner_lock_created_by = NULL WHERE id = p_event_id; -- Return true if update was successful RETURN FOUND; END; $$ LANGUAGE plpgsql;