🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
144 lines
4.4 KiB
PL/PgSQL
144 lines
4.4 KiB
PL/PgSQL
-- 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; |