diff --git a/assets/pasted-20260220-222757-27e58242.png b/assets/pasted-20260220-222757-27e58242.png new file mode 100644 index 0000000..e84f9bb Binary files /dev/null and b/assets/pasted-20260220-222757-27e58242.png differ diff --git a/assets/pasted-20260220-224107-f358f1b7.png b/assets/pasted-20260220-224107-f358f1b7.png new file mode 100644 index 0000000..cf8f196 Binary files /dev/null and b/assets/pasted-20260220-224107-f358f1b7.png differ diff --git a/assets/pasted-20260220-230123-feffa54b.png b/assets/pasted-20260220-230123-feffa54b.png new file mode 100644 index 0000000..80c7b00 Binary files /dev/null and b/assets/pasted-20260220-230123-feffa54b.png differ diff --git a/check_divs.php b/check_divs.php new file mode 100644 index 0000000..3ef77f2 --- /dev/null +++ b/check_divs.php @@ -0,0 +1,19 @@ + $line) { + $line_open = substr_count($line, '= 760 && ($i + 1) <= 780) { + echo "Line " . ($i + 1) . ": Depth $old_depth -> $depth | " . trim($line) . "\n"; + } +} +echo "Final depth: $depth\n"; diff --git a/check_tags.py b/check_tags.py new file mode 100644 index 0000000..d95bf77 --- /dev/null +++ b/check_tags.py @@ -0,0 +1,27 @@ + +import sys + +def check_html_balance(filename): + with open(filename, 'r') as f: + content = f.read() + + # Simple regex to find tags, ignoring PHP for now + import re + tags = re.findall(r'<(/?div|/?span|/?form|/?section|/?article|/?aside|/?header|/?footer|/?nav|/?main)', content) + + stack = [] + for i, tag in enumerate(tags): + if tag.startswith('/'): + if not stack: + print(f"Error: Closing tag {tag} with no opening tag at index {i}") + else: + stack.pop() + else: + stack.append(tag) + + if stack: + print(f"Error: Unbalanced tags remaining: {stack}") + else: + print("Tags are balanced (excluding potential PHP issues)") + +check_html_balance('index.php') diff --git a/db/migrations/20260220_create_poll_votes.sql b/db/migrations/20260220_create_poll_votes.sql new file mode 100644 index 0000000..af29308 --- /dev/null +++ b/db/migrations/20260220_create_poll_votes.sql @@ -0,0 +1,12 @@ +-- Migration to add poll votes table +CREATE TABLE IF NOT EXISTS `poll_votes` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `message_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + `option_index` int(11) NOT NULL, + `created_at` timestamp NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`), + UNIQUE KEY `user_poll_option` (`message_id`,`user_id`,`option_index`), + CONSTRAINT `poll_votes_ibfk_1` FOREIGN KEY (`message_id`) REFERENCES `messages` (`id`) ON DELETE CASCADE, + CONSTRAINT `poll_votes_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/fix_index.py b/fix_index.py new file mode 100644 index 0000000..1456fd1 --- /dev/null +++ b/fix_index.py @@ -0,0 +1,265 @@ +import sys + +with open('index.php', 'r') as f: + lines = f.readlines() + +start_marker = "" in line and i > 1200: # around there + else_line = i + break + +if not else_line: + print("Error: Could not find the final else line") + sys.exit(1) + +# Now find the first foreach after this else +start_line = 0 +for i in range(else_line, len(lines)): + if start_marker in lines[i]: + start_line = i + break + +if not start_line: + print("Error: Could not find start marker after else") + sys.exit(1) + +# Now find the end of this block. It should end with +# But I might have multiple ones now. +# We want to find the one that is followed by (closing the main if) +# and then (closing chat-container or messages-list) + +end_line = 0 +for i in range(start_line, len(lines)): + if "" in lines[i]: + # Check if next line (or soon after) is + is_real_end = False + for j in range(i+1, min(i+10, len(lines))): + if "" in lines[j]: + is_real_end = True + end_line = j + break + if is_real_end: + break + +if not end_line: + print("Error: Could not find end marker") + sys.exit(1) + +print(f"Replacing lines {start_line+1} to {end_line+1}") + +new_block = """ +
+
">
+
+
+ "> + + + + + + + + Épinglé + + +
+
+ + +
+ + Attachment + + + + + + +
+ + + +
+
📊 SONDAGE
+ +
+ + +
+ + + +
+ $opt): + $count = 0; + $user_voted = false; + if (isset($m['votes_data'])) { + foreach($m['votes_data'] as $v) { + if ($v['option_index'] == $idx) { + $count = (int)$v['vote_count']; + $user_ids = explode(',', $v['user_ids'] ?? ''); + if (in_array($current_user_id, $user_ids)) { + $user_voted = true; + } + break; + } + } + } + $percent = $total_votes > 0 ? round(($count / $total_votes) * 100) : 0; + $is_expired = !empty($meta['end_date']) && strtotime($meta['end_date']) < time(); + ?> +
+
+
+ + % () +
+
+ +
+ +
+ +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ + +
+ + + + + + +
+ +
+ +
+ + +
+
+ prepare("SELECT emoji, COUNT(*) as count, GROUP_CONCAT(user_id) as users FROM message_reactions WHERE message_id = ? GROUP BY emoji"); + $stmt_react->execute([$m['id']]); + $reactions = $stmt_react->fetchAll(); + foreach ($reactions as $r): + $reacted = in_array($current_user_id, explode(',', $r['users'])); + ?> + + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + """ + +# Adjust end_line to be the last endif before the start of next section +# The original file has at line 1486 in my previous read. +# Let's verify. + +with open('index.php', 'w') as f: + f.writelines(lines[:start_line]) + f.write(new_block) + f.write("\n") + f.writelines(lines[end_line+1:]) + diff --git a/fix_index_v2.py b/fix_index_v2.py new file mode 100644 index 0000000..4cabbc2 --- /dev/null +++ b/fix_index_v2.py @@ -0,0 +1,222 @@ +import sys + +with open('index.php', 'r') as f: + lines = f.readlines() + +# Section starts after line 1294 (index 1294) +# Section ends before chat-input-container (Line 1749 -> index 1748) +start_index = 1294 +end_index = 0 +for i, line in enumerate(lines): + if '
' in line: + end_index = i + break + +if not end_index: + print("Error: Could not find end marker") + sys.exit(1) + +print(f"Replacing lines {start_index+1} to {end_index}") + +new_content = """ +
+
">
+
+
+ "> + + + + + + + + Épinglé + + +
+
+ + +
+ + Attachment + + + + + + +
+ + + +
+
📊 SONDAGE
+ +
+ + +
+ + + +
+ $opt): + $count = 0; + $user_voted = false; + if (isset($m['votes_data'])) { + foreach($m['votes_data'] as $v) { + if ($v['option_index'] == $idx) { + $count = (int)$v['vote_count']; + $user_ids = explode(',', $v['user_ids'] ?? ''); + if (in_array($current_user_id, $user_ids)) { + $user_voted = true; + } + break; + } + } + } + $percent = $total_votes > 0 ? round(($count / $total_votes) * 100) : 0; + $is_expired = !empty($meta['end_date']) && strtotime($meta['end_date']) < time(); + ?> +
+
+
+ + % () +
+
+ +
+ +
+ +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ + +
+ + + + + + +
+ +
+ +
+ + +
+
+ prepare("SELECT emoji, COUNT(*) as count, GROUP_CONCAT(user_id) as users FROM message_reactions WHERE message_id = ? GROUP BY emoji"); + $stmt_react->execute([$m['id']]); + $reactions = $stmt_react->fetchAll(); + foreach ($reactions as $r): + $reacted = in_array($current_user_id, explode(',', $r['users'])); + ?> + + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +
+
+""" + +with open('index.php', 'w') as f: + f.writelines(lines[:start_index]) + f.write(new_content) + f.write("\n") + f.writelines(lines[end_index:]) + diff --git a/fix_index_v3.py b/fix_index_v3.py new file mode 100644 index 0000000..5b06a39 --- /dev/null +++ b/fix_index_v3.py @@ -0,0 +1,815 @@ +import sys +import re + +with open('index.php', 'r') as f: + content = f.read() + +# First, let's restore the thread loop (the first one) +thread_loop_pattern = r'<\?php foreach\(\$messages as \$m\):.*?\<\?php endforeach; \?\>' +# We need a non-greedy regex that handles nested PHP tags +# Actually, it's easier to find the markers. + +# Let's find the first foreach($messages as $m) +# and the first endforeach after it. + +# I'll just use a simpler approach: +# Find everything between
+# and
+# and replace it with a clean version of both loops. + +start_marker = '
' +end_marker = '
' + +start_pos = content.find(start_marker) +end_pos = content.find(end_marker) + +if start_pos == -1 or end_pos == -1: + print("Error: Could not find markers") + sys.exit(1) + +# Now we need to keep the structure between those markers but clean it. +# The structure is: +# if($active_thread): +# ... +# foreach($messages as $m): (thread loop) +# ... +# endforeach +# ... +# elseif($channel_type === 'event'): +# ... +# else: (normal chat) +# ... +# foreach($messages as $m): (normal loop) +# ... +# endforeach +# endif + +clean_inner = """ + +
+
+ ← Retour au forum +
+ + + + + + + + + +
+
+

+ + + Discussion : +

+ prepare("SELECT ft.* FROM forum_tags ft JOIN thread_tags tt ON ft.id = tt.tag_id WHERE tt.thread_id = ?"); + $stmt_t->execute([$active_thread['id']]); + $thread_tags = $stmt_t->fetchAll(); + if ($thread_tags): + foreach ($thread_tags as $t): + ?> + + +
+ +
+
">
+
+
+ "> + + + + + + SOLUTION + +
+
+ +
+ +
+
📊 SONDAGE
+ +
+ + +
+ + + +
+ $opt): + $count = 0; + $user_voted = false; + if (isset($m['votes_data'])) { + foreach($m['votes_data'] as $v) { + if ($v['option_index'] == $idx) { + $count = (int)$v['vote_count']; + $user_ids = explode(',', $v['user_ids'] ?? ''); + if (in_array($current_user_id, $user_ids)) { + $user_voted = true; + } + break; + } + } + } + $percent = $total_votes > 0 ? round(($count / $total_votes) * 100) : 0; + $is_expired = !empty($meta['end_date']) && strtotime($meta['end_date']) < time(); + ?> +
+
+
+ + % () +
+
+ +
+ +
+ +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ + +
+ + + + + + +
+ +
+ +
+ + +
+ prepare("SELECT emoji, COUNT(*) as count, GROUP_CONCAT(user_id) as users FROM message_reactions WHERE message_id = ? GROUP BY emoji"); + $stmt_react->execute([$m['id']]); + $reactions = $stmt_react->fetchAll(); + foreach ($reactions as $r): + $reacted = in_array($current_user_id, explode(',', $r['users'])); + ?> + + + + + + +
+
+ + + + + + + + + + + + + +
+
+
+ +
+
+ +
+
+
+

Événements

+

Découvrez et gérez les événements à venir.

+
+ + + +
+ +
+ +
+
+ +
+

Aucun événement prévu pour le moment.

+ +

Cliquez sur "Ajouter un événement" pour commencer.

+ +
+ + +
+
+
">
+
+
+
+
+ +
+
+ + + à + +
+ +
+ + + Fin: à + +
+ + +
+ + + + +
+ +
+
+ +
+
Voir plus
+ + +
+
+ Participants () +
+ prepare("SELECT u.avatar_url, u.display_name FROM event_participations ep JOIN users u ON ep.user_id = u.id WHERE ep.event_id = ? LIMIT 5"); + $stmt_p->execute([$event['id']]); + $participants = $stmt_p->fetchAll(); + $p_idx = 0; + foreach ($participants as $p): + ?> +
; margin-left: 0 ? '-8px' : '0'; ?>; position: relative; z-index: ;">
+ + 5): ?> +
+
+ +
+
+ +
+ +
+ +
+
+ + +
+
+ +
+

📜

+
+ +
+
+ . + +
+ +
+ + + + +
+ +
+ +
+ + + + + + + prepare("SELECT 1 FROM rule_acceptances WHERE user_id = ? AND channel_id = ?"); + $stmtAcc->execute([$current_user_id, $active_channel_id]); + $has_accepted = $stmtAcc->fetch(); + ?> +
+ +
+ Vous avez accepté les règles. +
+
+ +
+ +

Veuillez accepter les règles pour obtenir l'accès complet.

+ + +
+ +
+ +
+

🛡️

+

Cliquez sur un bouton pour vous attribuer ou vous retirer un rôle.

+ +
+ prepare("SELECT 1 FROM user_roles WHERE user_id = ? AND role_id = ?"); + $stmtHasRole->execute([$current_user_id, $ar['role_id']]); + $has_role = $stmtHasRole->fetch(); + ?> +
+ + +
+ +
+ + + + + +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+
+
+

🏛️

+
+ + Tous + + "> + + + +
+
+
+ + + + + + +
+
+ +
+ + +
+
+

+ + + +

+
+ Par • Dans # +
+
+ + Retour au forum + +
+ + +
+

Bienvenue dans # !

+

C'est le début du salon #.

+
+ + +
+
">
+
+
+ "> + + + + + + + + Épinglé + + +
+
+ +
+ +
+ + Attachment + + + + + + +
+ + + +
+
📊 SONDAGE
+ +
+ + +
+ + + +
+ $opt): + $count = 0; + $user_voted = false; + if (isset($m['votes_data'])) { + foreach($m['votes_data'] as $v) { + if ($v['option_index'] == $idx) { + $count = (int)$v['vote_count']; + $user_ids = explode(',', $v['user_ids'] ?? ''); + if (in_array($current_user_id, $user_ids)) { + $user_voted = true; + } + break; + } + } + } + $percent = $total_votes > 0 ? round(($count / $total_votes) * 100) : 0; + $is_expired = !empty($meta['end_date']) && strtotime($meta['end_date']) < time(); + ?> +
+
+
+ + % () +
+
+ +
+ +
+ +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ + +
+ + + + + + +
+ +
+ +
+ + +
+ prepare("SELECT emoji, COUNT(*) as count, GROUP_CONCAT(user_id) as users FROM message_reactions WHERE message_id = ? GROUP BY emoji"); + $stmt_react->execute([$m['id']]); + $reactions = $stmt_react->fetchAll(); + foreach ($reactions as $r): + $reacted = in_array($current_user_id, explode(',', $r['users'])); + ?> + + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + +""" + +new_content = clean_inner.strip() +content = content[:start_pos + len(start_marker)] + "\n" + new_content + "\n" + content[end_pos:] + +with open('index.php', 'w') as f: + f.write(content) + diff --git a/index.php_partial_fix b/index.php_partial_fix new file mode 100644 index 0000000..4f618ac --- /dev/null +++ b/index.php_partial_fix @@ -0,0 +1,104 @@ + +
+
📊 SONDAGE
+ +
+ + +
+ + + +
+ $opt): + $count = 0; + $user_voted = false; + if (isset($m['votes_data'])) { + foreach($m['votes_data'] as $v) { + if ($v['option_index'] == $idx) { + $count = $v['vote_count']; + $user_ids = explode(',', $v['user_ids'] ?? ''); + if (in_array($current_user_id, $user_ids)) { + $user_voted = true; + } + break; + } + } + } + $percent = $total_votes > 0 ? round(($count / $total_votes) * 100) : 0; + $is_expired = !empty($meta['end_date']) && strtotime($meta['end_date']) < time(); + ?> +
+
+
+ + % () +
+
+ +
+ +
+ +
+ +
+ + + + + +
+ + + +
+ +
+ + +
+ +
+ + +
+ + + + + + +
+ +
+ +
+ + \ No newline at end of file diff --git a/test_poll.php b/test_poll.php new file mode 100644 index 0000000..2d470eb --- /dev/null +++ b/test_poll.php @@ -0,0 +1,30 @@ + 1, + 'content' => 'bha a vous de choisir !', + 'is_poll' => '1', + 'poll_title' => 'Test du sondage !', + 'poll_color' => '#f45571', + 'poll_choice_type' => 'single', + 'poll_end_date' => '20/02/2026 23:45', + 'poll_options' => '["Oui je le veux !","Non je ne le veux pas !","Je ne sais pas encore !"]' +]; + +function getallheaders() { return []; } + +// Mock session +if (session_status() === PHP_SESSION_NONE) { + session_start(); +} +$_SESSION['user_id'] = 2; + +// Include the file +ob_start(); +include 'api_v1_messages.php'; +$output = ob_get_clean(); + +echo $output;