223 lines
No EOL
9.7 KiB
PL/PgSQL
223 lines
No EOL
9.7 KiB
PL/PgSQL
-- Migration pour les fonctionnalités avancées du serveur de chat
|
|
-- Exécuter après les migrations de base
|
|
|
|
-- Table des sanctions/modération
|
|
CREATE TABLE IF NOT EXISTS sanctions (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
moderator_id UUID NOT NULL REFERENCES users(id), -- NULL pour système automatique
|
|
sanction_type VARCHAR(50) NOT NULL, -- JSON serialized SanctionType
|
|
reason VARCHAR(100) NOT NULL, -- JSON serialized SanctionReason
|
|
message TEXT, -- Message optionnel du modérateur
|
|
expires_at TIMESTAMP WITH TIME ZONE, -- Expiration pour sanctions temporaires
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Index pour les sanctions
|
|
CREATE INDEX idx_sanctions_user_id ON sanctions(user_id);
|
|
CREATE INDEX idx_sanctions_active ON sanctions(user_id, is_active) WHERE is_active = true;
|
|
|
|
-- Table des réactions aux messages
|
|
CREATE TABLE IF NOT EXISTS message_reactions (
|
|
id SERIAL PRIMARY KEY,
|
|
message_id UUID NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
reaction_type VARCHAR(100) NOT NULL, -- JSON serialized ReactionType
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
-- Un utilisateur ne peut avoir qu'une réaction de chaque type par message
|
|
UNIQUE(message_id, user_id, reaction_type)
|
|
);
|
|
|
|
-- Index pour les réactions
|
|
CREATE INDEX idx_message_reactions_message ON message_reactions(message_id);
|
|
|
|
-- Table des blocages entre utilisateurs
|
|
CREATE TABLE IF NOT EXISTS user_blocks (
|
|
id SERIAL PRIMARY KEY,
|
|
blocker_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
blocked_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
reason VARCHAR(255),
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
-- Un utilisateur ne peut bloquer un autre qu'une seule fois
|
|
UNIQUE(blocker_id, blocked_id),
|
|
|
|
-- Un utilisateur ne peut pas se bloquer lui-même
|
|
CHECK (blocker_id != blocked_id)
|
|
);
|
|
|
|
-- Index pour les blocages
|
|
CREATE INDEX idx_user_blocks_blocker ON user_blocks(blocker_id);
|
|
CREATE INDEX idx_user_blocks_blocked ON user_blocks(blocked_id);
|
|
|
|
-- Table des salons avec métadonnées
|
|
CREATE TABLE IF NOT EXISTS rooms (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(50) NOT NULL UNIQUE,
|
|
display_name VARCHAR(100),
|
|
description TEXT,
|
|
creator_id UUID NOT NULL REFERENCES users(id),
|
|
is_private BOOLEAN NOT NULL DEFAULT false,
|
|
max_members INTEGER DEFAULT 100,
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Index pour les salons
|
|
CREATE INDEX idx_rooms_name ON rooms(name);
|
|
CREATE INDEX idx_rooms_creator ON rooms(creator_id);
|
|
CREATE INDEX idx_rooms_private ON rooms(is_private);
|
|
|
|
-- Table des membres de salons avec rôles
|
|
CREATE TABLE IF NOT EXISTS room_members (
|
|
id SERIAL PRIMARY KEY,
|
|
room_id INTEGER NOT NULL REFERENCES rooms(id) ON DELETE CASCADE,
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
role VARCHAR(20) NOT NULL DEFAULT 'member', -- 'admin', 'moderator', 'member'
|
|
joined_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
last_read_at TIMESTAMP WITH TIME ZONE,
|
|
|
|
UNIQUE(room_id, user_id)
|
|
);
|
|
|
|
-- Index pour les membres de salon
|
|
CREATE INDEX idx_room_members_room ON room_members(room_id);
|
|
CREATE INDEX idx_room_members_user ON room_members(user_id);
|
|
CREATE INDEX idx_room_members_role ON room_members(room_id, role);
|
|
|
|
-- Table des notifications
|
|
CREATE TABLE IF NOT EXISTS notifications (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
type VARCHAR(50) NOT NULL, -- 'dm', 'mention', 'room_invite', etc.
|
|
title VARCHAR(255) NOT NULL,
|
|
content TEXT NOT NULL,
|
|
metadata JSONB, -- Données additionnelles spécifiques au type
|
|
is_read BOOLEAN NOT NULL DEFAULT false,
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
read_at TIMESTAMP WITH TIME ZONE
|
|
);
|
|
|
|
-- Index pour les notifications
|
|
CREATE INDEX idx_notifications_user ON notifications(user_id);
|
|
CREATE INDEX idx_notifications_unread ON notifications(user_id, is_read) WHERE is_read = false;
|
|
CREATE INDEX idx_notifications_type ON notifications(type);
|
|
|
|
-- Table des sessions utilisateur (pour la gestion des connexions multiples)
|
|
CREATE TABLE IF NOT EXISTS user_sessions (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
session_token VARCHAR(255) NOT NULL UNIQUE,
|
|
device_info VARCHAR(255), -- User-Agent ou info appareil
|
|
ip_address INET,
|
|
last_activity TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
is_active BOOLEAN NOT NULL DEFAULT true
|
|
);
|
|
|
|
-- Index pour les sessions
|
|
CREATE INDEX idx_user_sessions_user ON user_sessions(user_id);
|
|
CREATE INDEX idx_user_sessions_token ON user_sessions(session_token);
|
|
CREATE INDEX idx_user_sessions_active ON user_sessions(user_id, is_active) WHERE is_active = true;
|
|
CREATE INDEX idx_user_sessions_expires ON user_sessions(expires_at);
|
|
|
|
-- Table des logs d'audit pour le monitoring
|
|
CREATE TABLE IF NOT EXISTS audit_logs (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id UUID REFERENCES users(id), -- NULL pour les actions système
|
|
action VARCHAR(100) NOT NULL, -- 'login', 'message_sent', 'user_banned', etc.
|
|
resource_type VARCHAR(50), -- 'user', 'message', 'room', etc.
|
|
resource_id VARCHAR(100), -- ID de la ressource concernée
|
|
details JSONB, -- Détails spécifiques à l'action
|
|
ip_address INET,
|
|
user_agent TEXT,
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Index pour les logs d'audit
|
|
CREATE INDEX idx_audit_logs_user ON audit_logs(user_id);
|
|
CREATE INDEX idx_audit_logs_action ON audit_logs(action);
|
|
CREATE INDEX idx_audit_logs_resource ON audit_logs(resource_type, resource_id);
|
|
CREATE INDEX idx_audit_logs_created ON audit_logs(created_at);
|
|
|
|
-- Mise à jour de la table messages pour supporter plus de métadonnées
|
|
ALTER TABLE messages
|
|
ADD COLUMN IF NOT EXISTS message_type VARCHAR(20) DEFAULT 'text',
|
|
ADD COLUMN IF NOT EXISTS reply_to_id UUID REFERENCES messages(id),
|
|
ADD COLUMN IF NOT EXISTS is_edited BOOLEAN DEFAULT false,
|
|
ADD COLUMN IF NOT EXISTS edited_at TIMESTAMP WITH TIME ZONE,
|
|
ADD COLUMN IF NOT EXISTS metadata JSONB;
|
|
|
|
-- Index pour les nouvelles colonnes de messages
|
|
CREATE INDEX IF NOT EXISTS idx_messages_type ON messages(message_type);
|
|
CREATE INDEX IF NOT EXISTS idx_messages_reply ON messages(reply_to_id);
|
|
CREATE INDEX IF NOT EXISTS idx_messages_edited ON messages(is_edited) WHERE is_edited = true;
|
|
|
|
-- Mise à jour de la table users pour supporter les rôles et statuts
|
|
ALTER TABLE users
|
|
ADD COLUMN IF NOT EXISTS role VARCHAR(20) DEFAULT 'user',
|
|
ADD COLUMN IF NOT EXISTS status VARCHAR(20) DEFAULT 'offline',
|
|
ADD COLUMN IF NOT EXISTS last_seen TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
ADD COLUMN IF NOT EXISTS reputation_score INTEGER DEFAULT 100,
|
|
ADD COLUMN IF NOT EXISTS is_banned BOOLEAN DEFAULT false,
|
|
ADD COLUMN IF NOT EXISTS is_muted BOOLEAN DEFAULT false;
|
|
|
|
-- Index pour les nouvelles colonnes utilisateurs
|
|
CREATE INDEX IF NOT EXISTS idx_users_role ON users(role);
|
|
CREATE INDEX IF NOT EXISTS idx_users_status ON users(status);
|
|
|
|
-- Vue pour les statistiques en temps réel
|
|
CREATE OR REPLACE VIEW server_stats AS
|
|
SELECT
|
|
(SELECT COUNT(*) FROM users WHERE last_seen > CURRENT_TIMESTAMP - INTERVAL '5 minutes') as active_users,
|
|
(SELECT COUNT(*) FROM users) as total_users,
|
|
(SELECT COUNT(*) FROM messages WHERE created_at > CURRENT_DATE) as messages_today,
|
|
(SELECT COUNT(*) FROM messages) as total_messages;
|
|
|
|
-- Fonction pour nettoyer les sessions expirées
|
|
CREATE OR REPLACE FUNCTION cleanup_expired_sessions()
|
|
RETURNS INTEGER AS $$
|
|
DECLARE
|
|
deleted_count INTEGER;
|
|
BEGIN
|
|
DELETE FROM user_sessions WHERE expires_at < CURRENT_TIMESTAMP;
|
|
GET DIAGNOSTICS deleted_count = ROW_COUNT;
|
|
RETURN deleted_count;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Fonction pour nettoyer les anciens logs d'audit (garder 30 jours)
|
|
CREATE OR REPLACE FUNCTION cleanup_old_audit_logs()
|
|
RETURNS INTEGER AS $$
|
|
DECLARE
|
|
deleted_count INTEGER;
|
|
BEGIN
|
|
DELETE FROM audit_logs WHERE created_at < CURRENT_TIMESTAMP - INTERVAL '30 days';
|
|
GET DIAGNOSTICS deleted_count = ROW_COUNT;
|
|
RETURN deleted_count;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Contraintes de sécurité
|
|
ALTER TABLE messages ADD CONSTRAINT chk_message_content_length CHECK (length(content) <= 4000);
|
|
ALTER TABLE rooms ADD CONSTRAINT chk_room_name_length CHECK (length(name) <= 50 AND length(name) >= 1);
|
|
ALTER TABLE rooms ADD CONSTRAINT chk_room_max_members CHECK (max_members > 0 AND max_members <= 1000);
|
|
|
|
-- Commentaires pour la documentation
|
|
COMMENT ON TABLE sanctions IS 'Table des sanctions de modération (warnings, mutes, bans)';
|
|
COMMENT ON TABLE message_reactions IS 'Table des réactions aux messages (like, love, etc.)';
|
|
COMMENT ON TABLE user_blocks IS 'Table des blocages entre utilisateurs';
|
|
COMMENT ON TABLE rooms IS 'Table des salons de chat avec métadonnées';
|
|
COMMENT ON TABLE room_members IS 'Table des membres de salon avec leurs rôles';
|
|
COMMENT ON TABLE notifications IS 'Table des notifications push/in-app';
|
|
COMMENT ON TABLE user_sessions IS 'Table des sessions utilisateur actives';
|
|
COMMENT ON TABLE audit_logs IS 'Table des logs d''audit pour le monitoring';
|
|
|
|
COMMENT ON VIEW server_stats IS 'Vue des statistiques serveur en temps réel';
|
|
|
|
-- Permissions par défaut (ajuster selon vos besoins)
|
|
-- GRANT SELECT ON server_stats TO chat_readonly_user;
|
|
-- GRANT SELECT, INSERT ON audit_logs TO chat_api_user; |