diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..b3f2c9c --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,239 @@ +:root { + --background-primary: #36393f; + --background-secondary: #2f3136; + --background-tertiary: #202225; + --channel-color: #8e9297; + --text-normal: #dcddde; + --text-muted: #72767d; + --interactive-normal: #b9bbbe; + --interactive-hover: #dcddde; + --interactive-active: #fff; + --background-modifier-hover: rgba(79,84,92,0.16); + --background-modifier-active: rgba(79,84,92,0.24); + --border-color: rgba(0,0,0,0.2); +} + +body, html { + height: 100%; + margin: 0; + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + background-color: var(--background-primary); + color: var(--text-normal); + overflow: hidden; +} + +.app-container { + display: flex; + height: 100vh; +} + +/* Servers List */ +.servers-list { + width: 72px; + background-color: var(--background-tertiary); + padding-top: 12px; + display: flex; + flex-direction: column; + align-items: center; + overflow-y: auto; +} + +.server-icon { + width: 48px; + height: 48px; + border-radius: 50%; + background-color: var(--background-primary); + margin-bottom: 8px; + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + font-weight: bold; + cursor: pointer; + transition: all 0.2s ease; + position: relative; +} + +.server-icon:hover, .server-icon.active { + border-radius: 16px; + background-color: #5865f2; /* Discord blurple */ +} + +.server-icon.add-server-btn { + background-color: var(--background-secondary); + color: #43b581; /* Discord green */ + font-size: 24px; +} + +.server-icon.add-server-btn:hover { + background-color: #43b581; + color: white; +} + + +/* Channels & User Panel */ +.sidebar { + width: 240px; + background-color: var(--background-secondary); + display: flex; + flex-direction: column; +} + +.sidebar-header { + padding: 0 16px; + height: 48px; + display: flex; + align-items: center; + border-bottom: 1px solid var(--border-color); + font-weight: bold; + font-size: 16px; +} + +.channels-list { + flex-grow: 1; + padding: 16px 8px; + overflow-y: auto; +} + +.channel { + padding: 6px 8px; + border-radius: 4px; + cursor: pointer; + display: flex; + align-items: center; + font-weight: 500; + color: var(--channel-color); +} + +.channel:before { + content: '#'; + margin-right: 6px; + font-size: 20px; + color: var(--text-muted); +} + +.channel:hover { + background-color: var(--background-modifier-hover); + color: var(--interactive-hover); +} + +.channel.active { + background-color: var(--background-modifier-active); + color: var(--interactive-active); +} + +.user-panel { + height: 52px; + background-color: #292b2f; + padding: 0 8px; + display: flex; + align-items: center; + justify-content: space-between; +} + +.user-info { + display: flex; + align-items: center; +} + +.user-avatar { + width: 32px; + height: 32px; + border-radius: 50%; + background-color: #7289da; + margin-right: 8px; +} + +.user-name { + font-weight: 600; + font-size: 14px; +} + +.logout-btn { + color: var(--text-muted); + cursor: pointer; + padding: 4px; +} +.logout-btn:hover { + color: var(--interactive-hover); +} + + +/* Chat Area */ +.chat-container { + flex-grow: 1; + display: flex; + flex-direction: column; + background-color: var(--background-primary); +} + +.chat-header { + height: 48px; + padding: 0 16px; + display: flex; + align-items: center; + border-bottom: 1px solid var(--border-color); + font-weight: bold; +} + +.chat-header:before { + content: '#'; + margin-right: 6px; + font-size: 24px; + color: var(--text-muted); +} + +.messages-list { + flex-grow: 1; + overflow-y: auto; + padding: 20px; +} + +.message { + display: flex; + margin-bottom: 16px; +} + +.message-avatar { + width: 40px; + height: 40px; + border-radius: 50%; + background-color: #7289da; + margin-right: 16px; + flex-shrink: 0; +} + +.message-content { + display: flex; + flex-direction: column; +} + +.message-author { + font-weight: 500; + color: var(--text-normal); + margin-bottom: 4px; +} + +.message-text { + line-height: 1.4; +} + +.chat-input-form { + padding: 0 20px 20px 20px; +} + +.chat-input { + width: 100%; + height: 44px; + border-radius: 8px; + background-color: #40444b; + border: none; + padding: 0 16px; + color: var(--text-normal); + font-size: 16px; + box-sizing: border-box; +} + +.chat-input::placeholder { + color: var(--text-muted); +} diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..e69de29 diff --git a/create_server.php b/create_server.php new file mode 100644 index 0000000..3b34b2d --- /dev/null +++ b/create_server.php @@ -0,0 +1,102 @@ +beginTransaction(); + + // 1. Insert the new server + $stmt = $pdo->prepare("INSERT INTO servers (name, owner_id) VALUES (:name, :owner_id)"); + $stmt->execute(['name' => $server_name, 'owner_id' => $user_id]); + $server_id = $pdo->lastInsertId(); + + // 2. Add the owner to the server_members table + $stmt = $pdo->prepare("INSERT INTO server_members (server_id, user_id) VALUES (:server_id, :user_id)"); + $stmt->execute(['server_id' => $server_id, 'user_id' => $user_id]); + + // 3. Create a default 'general' channel for the new server + $stmt = $pdo->prepare("INSERT INTO channels (server_id, name) VALUES (:server_id, :name)"); + $stmt->execute(['server_id' => $server_id, 'name' => 'general']); + + // Commit the transaction + $pdo->commit(); + + // Redirect to the main page after creation + header('Location: index.php'); + exit; + + } catch (PDOException $e) { + // Rollback the transaction if something failed + if ($pdo->inTransaction()) { + $pdo->rollBack(); + } + $error = "An error occurred while creating the server: " . $e->getMessage(); + } + } +} + +?> + + + + + + Create a New Server + + + + + +
+
+
+
+
+

Create Your Server

+

Give your new server a personality with a name. You can always change it later.

+ + +
+ + +
+
+ + +
+
+ +
+
+ +
+
+
+
+
+ + + + diff --git a/db/migrate.php b/db/migrate.php new file mode 100644 index 0000000..9191478 --- /dev/null +++ b/db/migrate.php @@ -0,0 +1,31 @@ +exec("CREATE TABLE IF NOT EXISTS servers ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + owner_id INT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (owner_id) REFERENCES users(id) + ) ENGINE=INNODB;"); + + // Migration for server_members table + $pdo->exec("CREATE TABLE IF NOT EXISTS server_members ( + id INT AUTO_INCREMENT PRIMARY KEY, + server_id INT NOT NULL, + user_id INT NOT NULL, + joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (server_id) REFERENCES servers(id) ON DELETE CASCADE, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, + UNIQUE KEY (server_id, user_id) + ) ENGINE=INNODB;"); + + echo "Database migration completed successfully! Tables 'servers' and 'server_members' are ready."; + +} catch (PDOException $e) { + die("Database migration failed: " . $e->getMessage()); +} \ No newline at end of file diff --git a/db/setup.php b/db/setup.php new file mode 100644 index 0000000..96cfef4 --- /dev/null +++ b/db/setup.php @@ -0,0 +1,33 @@ + PDO::ERRMODE_EXCEPTION, + ]); + + // Create the database if it doesn't exist + $pdo->exec("CREATE DATABASE IF NOT EXISTS " . DB_NAME); + echo "Database '" . DB_NAME . "' created or already exists.\n"; + + // Now, connect to the specific database using the helper + $pdo = db(); + + // Create the users table + $sql = " + CREATE TABLE IF NOT EXISTS users ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + simple_id VARCHAR(10) NOT NULL UNIQUE, + ultra_id VARCHAR(20) NOT NULL UNIQUE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + );"; + $pdo->exec($sql); + echo "Table 'users' created successfully (if it didn't exist).\n"; + +} catch (PDOException $e) { + die("DB SETUP ERROR: " . $e->getMessage()); +} +?> diff --git a/get_channels.php b/get_channels.php new file mode 100644 index 0000000..aecb9bb --- /dev/null +++ b/get_channels.php @@ -0,0 +1,55 @@ + 'Authentication required']); + http_response_code(401); + exit; +} + +// Server ID must be provided +if (!isset($_GET['server_id'])) { + echo json_encode(['error' => 'Server ID is missing']); + http_response_code(400); + exit; +} + +$user_id = $_SESSION['user_id']; +$server_id = (int)$_GET['server_id']; + +try { + $pdo = db(); + + // Security check: Ensure the user is a member of the server + $stmt = $pdo->prepare("SELECT 1 FROM server_members WHERE server_id = :server_id AND user_id = :user_id"); + $stmt->execute(['server_id' => $server_id, 'user_id' => $user_id]); + if ($stmt->fetchColumn() === false) { + echo json_encode(['error' => 'Access denied']); + http_response_code(403); + exit; + } + + // Fetch server details + $stmt = $pdo->prepare("SELECT name FROM servers WHERE id = :server_id"); + $stmt->execute(['server_id' => $server_id]); + $server = $stmt->fetch(PDO::FETCH_ASSOC); + + // Fetch channels for the server + $stmt = $pdo->prepare("SELECT id, name FROM channels WHERE server_id = :server_id ORDER BY name ASC"); + $stmt->execute(['server_id' => $server_id]); + $channels = $stmt->fetchAll(PDO::FETCH_ASSOC); + + echo json_encode([ + 'server' => $server, + 'channels' => $channels + ]); + +} catch (PDOException $e) { + echo json_encode(['error' => 'Database error']); + http_response_code(500); + // In a real app, you would log the error message, not expose it. +} diff --git a/get_messages.php b/get_messages.php new file mode 100644 index 0000000..99b3d90 --- /dev/null +++ b/get_messages.php @@ -0,0 +1,57 @@ + 'Unauthorized']); + exit(); +} + +$user_id = $_SESSION['user_id']; +$channel_id = $_GET['channel_id'] ?? null; + +if (!$channel_id) { + http_response_code(400); + echo json_encode(['error' => 'Channel ID is required']); + exit(); +} + +try { + $pdo = db(); + + // Verify user has access to this channel's server + $stmt = $pdo->prepare(" + SELECT c.id + FROM channels c + JOIN servers s ON c.server_id = s.id + JOIN server_members sm ON s.id = sm.server_id + WHERE c.id = ? AND sm.user_id = ? + "); + $stmt->execute([$channel_id, $user_id]); + if ($stmt->fetch() === false) { + http_response_code(403); + echo json_encode(['error' => 'Forbidden']); + exit(); + } + + // Fetch messages + $stmt = $pdo->prepare(" + SELECT m.id, m.content, m.created_at, u.username + FROM messages m + JOIN users u ON m.user_id = u.id + WHERE m.channel_id = ? + ORDER BY m.created_at ASC + "); + $stmt->execute([$channel_id]); + $messages = $stmt->fetchAll(); + + header('Content-Type: application/json'); + echo json_encode($messages); + +} catch (PDOException $e) { + error_log("Get Messages Error: " . $e->getMessage()); + http_response_code(500); + echo json_encode(['error' => 'Internal Server Error']); +} diff --git a/index.php b/index.php index 7205f3d..e717e65 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,238 @@ - - + + - - - New Style - - - - - - - - - - - - - - - - - - - + + + Discord V2 + -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

+
+ +
+ +
+ +
+ + + +
+ + + + + +
+
+ +
+
+ +
+ Sélectionnez un canal pour commencer à discuter. +
+
+ +
-
- + + - + \ No newline at end of file diff --git a/login.php b/login.php new file mode 100644 index 0000000..df96634 --- /dev/null +++ b/login.php @@ -0,0 +1,96 @@ +prepare("SELECT * FROM users WHERE username = ?"); + $stmt->execute([$username]); + $user = $stmt->fetch(); + + if ($user && password_verify($password, $user['password'])) { + // Password is correct, start session and redirect + session_regenerate_id(true); + $_SESSION['user_id'] = $user['id']; + $_SESSION['username'] = $user['username']; + + // Explicitly redirect + header("Location: index.php"); + // Fallback with JavaScript redirection + echo ''; + exit(); + } else { + $errors[] = 'Nom d\'utilisateur ou mot de passe incorrect.'; + } + } catch (PDOException $e) { + error_log("Login Error: " . $e->getMessage()); + $errors[] = 'Une erreur est survenue lors de la connexion. Veuillez réessayer.'; + } + } +} +?> + + + + + + Connexion - Discord V2 + + + +
+
+
+
+
+

Connexion

+
+
+ +
+ +

+ +
+ +
+
+ + +
+
+ + +
+ +
+
+ +
+
+
+
+ + \ No newline at end of file diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..ceaf227 --- /dev/null +++ b/logout.php @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/register.php b/register.php new file mode 100644 index 0000000..cac36be --- /dev/null +++ b/register.php @@ -0,0 +1,114 @@ +prepare("SELECT COUNT(*) FROM users WHERE username = ?"); + $stmt->execute([$username]); + if ($stmt->fetchColumn() > 0) { + $errors[] = 'Ce nom d\'utilisateur est déjà pris.'; + } else { + // Generate unique IDs + $simple_id = generateSimpleId(); + $ultra_id = generateUltraId(); + + // Hash password + $hashed_password = password_hash($password, PASSWORD_DEFAULT); + + // Insert user + $stmt = $pdo->prepare("INSERT INTO users (username, password, simple_id, ultra_id) VALUES (?, ?, ?, ?)"); + $stmt->execute([$username, $hashed_password, $simple_id, $ultra_id]); + + // Get the new user's ID + $user_id = $pdo->lastInsertId(); + + // Log the user in + $_SESSION['user_id'] = $user_id; + $_SESSION['username'] = $username; + + // Redirect to the main page + header("Location: index.php"); + exit(); + } + } catch (PDOException $e) { + error_log("Registration Error: " . $e->getMessage()); + $errors[] = 'Une erreur est survenue lors de l\'inscription. Veuillez réessayer.'; + } + } +} +?> + + + + + + Inscription - Discord V2 + + + +
+
+
+
+
+

Inscription

+
+
+ +
+ +

+ +
+ + +
+

+

Redirection vers la page de connexion...

+
+ +
+
+ + +
+
+ + +
+ +
+ +
+ +
+
+
+
+ + diff --git a/send_message.php b/send_message.php new file mode 100644 index 0000000..d5b3d33 --- /dev/null +++ b/send_message.php @@ -0,0 +1,68 @@ + 'Unauthorized']); + exit(); +} + +if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + http_response_code(405); + echo json_encode(['error' => 'Method Not Allowed']); + exit(); +} + +$user_id = $_SESSION['user_id']; +$data = json_decode(file_get_contents('php://input'), true); +$channel_id = $data['channel_id'] ?? null; +$content = $data['content'] ?? null; + +if (!$channel_id || !$content) { + http_response_code(400); + echo json_encode(['error' => 'Channel ID and content are required']); + exit(); +} + +$content = trim($content); +if (empty($content)) { + http_response_code(400); + echo json_encode(['error' => 'Message content cannot be empty']); + exit(); +} + +try { + $pdo = db(); + + // Verify user has access to this channel's server + $stmt = $pdo->prepare(" + SELECT c.id + FROM channels c + JOIN servers s ON c.server_id = s.id + JOIN server_members sm ON s.id = sm.server_id + WHERE c.id = ? AND sm.user_id = ? + "); + $stmt->execute([$channel_id, $user_id]); + if ($stmt->fetch() === false) { + http_response_code(403); + echo json_encode(['error' => 'Forbidden']); + exit(); + } + + // Insert message + $stmt = $pdo->prepare(" + INSERT INTO messages (channel_id, user_id, content) + VALUES (?, ?, ?) + "); + $stmt->execute([$channel_id, $user_id, $content]); + + header('Content-Type: application/json'); + echo json_encode(['success' => true, 'message' => 'Message sent']); + +} catch (PDOException $e) { + error_log("Send Message Error: " . $e->getMessage()); + http_response_code(500); + echo json_encode(['error' => 'Internal Server Error']); +} diff --git a/utils.php b/utils.php new file mode 100644 index 0000000..91aa1a7 --- /dev/null +++ b/utils.php @@ -0,0 +1,17 @@ + \ No newline at end of file