retour sur v5rc9

Locked by Fred · 15 Jan 2026 18:33 • Solved by arpinux · 14 Jan 2026 21:04
Avatar
Posts 132

salut :)

mise à jour effectuée sur v5rc8 sans soucis.

bugs :

  • impossible de marquer comme résolu
  • impossible d'épingler

logs en pj

Attachments
logs.zip
30.27 KBPlease log in to download files.
  • french Résolu
Avatar
Posts 243

Ah, tu vois, je te l’avais bien dit ! 😉
Mais cette fois, je reproduis facilement l’erreur de mon côté, je vais corriger ça tout de suite. Merci pour ton retour !

Avatar
Posts 132

bug groupes modifiés :
contexte : une fois l'installation rc9 faite, j'ai modifié le groupe "Membre" en "membre". une fois la modification appliquée, plusieurs utilisateurs sont venus s'inscrire, ce qui a créé automatiquement un nouveau groupe "Membre", rendant ainsi ma modification "membre" inutile.

Avatar
Posts 243

Bien vu !
J'ai corrigé les options de modération (épingles/fermetures/résolutions) dans l'archive en téléchargement via le lien officiel.
J'ai également résolu le problème lié au groupe.

Si tu ne souhaites pas mettre à jour toute l'archive, voici le fichier concerné :

  • app/Controllers/Auth/RegisterController.php
PHP

<?php  
/*
 * Project name: Flatboard 5
 * Project URL: https://flatboard.org
 * Author: Frédéric Kaplon and contributors
 * All Flatboard code is released under the GPL3 license.
 *
 * Flatboard 5 - Contrôleur Register
 */

namespace App\Controllers\Auth;

use App\Core\Controller;  
use App\Core\Session;  
use App\Core\Validator;  
use App\Core\RateLimiter;  
use App\Core\Config;  
use App\Models\User;  
use App\Services\EmailService;

class RegisterController extends Controller  
{  
    public function show()  
    {  
        if (Session::get('user_id')) {  
            $this->redirect(\App\Helpers\UrlHelper::to('/'));  
            return;  
        }

        $config = Config::getInstance();  
        if (!$config->get('registration_enabled', true)) {  
            Session::flash('error', \App\Helpers\Translator::trans('auth.registrationDisabled', [], 'errors'));  
            $this->redirect(\App\Helpers\UrlHelper::to('/'));  
            return;  
        }

        $config = Config::getInstance();  
        $forumTitle = $config->get('forum.title');  
        $forumDescription = $config->get('forum.description');  
        // Normaliser les chaînes vides en null  
        if ($forumTitle === '') {  
            $forumTitle = null;  
        }  
        if ($forumDescription === '') {  
            $forumDescription = null;  
        }  
        $siteDescription = $config->get('site_description', $forumDescription);  
        $pageTitle = \App\Helpers\Translator::trans('register.title', [], 'auth') ?: 'Register';

        $this->view('auth/register', [  
            'bannerType' => 'index',  
            'forumTitle' => $forumTitle,  
            'forumDescription' => $forumDescription,  
            'pageTitle' => $pageTitle,  
            'pageIcon' => 'fas fa-user-plus',  
            // SEO  
            'title' => $pageTitle,  
            'description' => $siteDescription,  
            'canonical' => '/register',  
        ], 'frontend');  
    }

    public function register()  
    {  
        $limiter = new RateLimiter();  
        $ip = $this->request->getIp();

        // Vérifier si l'IP est bannie  
        if (\App\Models\Ban::isIpBanned($ip)) {  
            $ban = \App\Models\Ban::getActiveByIp($ip);  
            \App\Core\Logger::security('Registration attempt from banned IP', [  
                'ip' => $ip,  
                'email' => $this->request->get('email'),  
                'ban_id' => $ban['id'] ?? null  
            ]);  
            Session::flash('error', \App\Helpers\Translator::trans('auth.account.banned', [], 'errors') ?: 'Votre adresse IP a été bannie.');  
            $this->redirect(\App\Helpers\UrlHelper::to('/register'));  
            return;  
        }

        if (!$limiter->check('register', $ip)) {  
            \App\Core\Logger::security('Rate limit exceeded for registration attempt', [  
                'ip' => $ip,  
                'email' => $this->request->get('email')  
            ]);  
            Session::flash('error', \App\Helpers\Translator::trans('auth.tooManyRegisterAttempts', [], 'errors'));  
            $this->redirect(\App\Helpers\UrlHelper::to('/register'));  
            return;  
        }

        $config = Config::getInstance();  
        if (!$config->get('registration_enabled', true)) {  
            Session::flash('error', \App\Helpers\Translator::trans('auth.registrationDisabled', [], 'errors'));  
            $this->redirect(\App\Helpers\UrlHelper::to('/'));  
            return;  
        }

        $validator = new Validator($this->request->all());  
        $validator->required('username')
            ->min('username', 3)
            ->max('username', 30)
            ->regex('username', '/^[a-zA-Z0-9_-]+$/', \App\Helpers\Translator::trans('validation.username.invalidFormat', [], 'errors') ?: 'Le nom d\'utilisateur ne peut contenir que des lettres, chiffres, tirets et underscores');  
        $validator->required('email')->email('email');  
        $validator->required('password')->min('password', 8)->confirmed('password');

        if (!$validator->isValid()) {  
            Session::flash('errors', $validator->getErrors());  
            $this->redirect(\App\Helpers\UrlHelper::to('/register'));  
            return;  
        }

        $username = $this->request->get('username');  
        $email = $this->request->get('email');  
        $password = $this->request->get('password');

        // Vérifier si l'utilisateur existe déjà  
        if (User::findByEmail($email)) {  
            \App\Core\Logger::warning('Registration attempt with existing email', [  
                'ip' => $ip,  
                'email' => $email,  
                'username' => $username  
            ]);  
            Session::flash('error', \App\Helpers\Translator::trans('validation.email.alreadyUsed', [], 'errors'));  
            $this->redirect(\App\Helpers\UrlHelper::to('/register'));  
            return;  
        }

        if (User::findByUsername($username)) {  
            \App\Core\Logger::warning('Registration attempt with existing username', [  
                'ip' => $ip,  
                'email' => $email,  
                'username' => $username  
            ]);  
            Session::flash('error', \App\Helpers\Translator::trans('validation.username.alreadyUsed', [], 'errors'));  
            $this->redirect(\App\Helpers\UrlHelper::to('/register'));  
            return;  
        }

        $emailVerificationEnabled = $config->get('email_verification', false);

        // Initialiser les groupes et permissions par défaut si nécessaire  
        \App\Models\Group::initDefaults();  
        \App\Helpers\PermissionHelper::initDefaults();

        // Récupérer le groupe membre via GroupHelper (utilise le champ 'type', pas le nom)  
        // Permet le renommage libre du groupe sans casser la fonctionnalité  
        $memberGroupId = \App\Helpers\GroupHelper::getMemberGroupId();

        if (!$memberGroupId) {  
            // Si aucun groupe membre n'existe après l'initialisation, c'est une erreur critique  
            \App\Core\Logger::error('Member group not found after initialization', [  
                'ip' => $ip  
            ]);  
            Session::flash('error', \App\Helpers\Translator::trans('auth.system.error', [], 'errors') ?: 'Erreur système : groupe membre introuvable');  
            $this->redirect(\App\Helpers\UrlHelper::to('/register'));  
            return;  
        }

        // Créer l'utilisateur avec le groupe membre par défaut  
        try {  
            $userId = User::create([  
                'username' => $username,  
                'email' => $email,  
                'password' => $password,  
                'email_verified' => !$emailVerificationEnabled,  
                'group_id' => $memberGroupId  
            ]);  
        } catch (\Exception $e) {  
            // Gérer les violations de contrainte UNIQUE (race condition)  
            if ($e->getCode() == 409 || strpos($e->getMessage(), 'already exists') !== false) {  
                if (strpos($e->getMessage(), 'Email') !== false) {  
                    \App\Core\Logger::warning('Registration failed: Email already exists (race condition)', [  
                        'ip' => $ip,  
                        'email' => $email,  
                        'username' => $username  
                    ]);  
                    Session::flash('error', \App\Helpers\Translator::trans('validation.email.alreadyUsed', [], 'errors'));  
                } elseif (strpos($e->getMessage(), 'Username') !== false) {  
                    \App\Core\Logger::warning('Registration failed: Username already exists (race condition)', [  
                        'ip' => $ip,  
                        'email' => $email,  
                        'username' => $username  
                    ]);  
                    Session::flash('error', \App\Helpers\Translator::trans('validation.username.alreadyUsed', [], 'errors'));  
                } else {  
                    Session::flash('error', \App\Helpers\Translator::trans('general.errorOccurred', [], 'errors') ?: 'Erreur lors de l\'inscription');  
                }  
                $this->redirect(\App\Helpers\UrlHelper::to('/register'));  
                return;  
            }  
            // Relancer l'exception si ce n'est pas une contrainte UNIQUE  
            throw $e;  
        }

        \App\Core\Logger::info('New user registered', [  
            'user_id' => $userId,  
            'username' => $username,  
            'email' => $email,  
            'ip' => $ip,  
            'email_verified' => !$emailVerificationEnabled,  
            'group_id' => $memberGroupId  
        ]);

        // Déclencher l'événement user.registered via les plugins  
        if (class_exists('\App\Core\Plugin')) {  
            $createdUser = User::find($userId);  
            if ($createdUser) {  
                \App\Core\Plugin::trigger('user.registered', $createdUser);  
            }  
        }

        // Envoyer l'email de vérification si nécessaire  
        if ($emailVerificationEnabled) {  
            $token = bin2hex(random_bytes(32));  
            $expiresAt = time() + (3600 * 24 * 7); // 7 jours

            // Stocker le token  
            $storage = \App\Storage\StorageFactory::create();  
            $storage->createEmailVerificationToken($userId, $token, $expiresAt);

            // Envoyer l'email  
            $emailService = new EmailService();  
            $siteUrl = rtrim($config->get('site_url', ''), '/');  
            $verificationUrl = $siteUrl . '/verify-email?token=' . $token;  
            $emailService->sendVerification($email, $token, $verificationUrl);

            Session::flash('success', \App\Helpers\Translator::trans('register.successVerifyEmail', [], 'auth'));  
            $this->redirect(\App\Helpers\UrlHelper::to('/login'));  
        } else {  
            // Connecter automatiquement si la vérification email n'est pas activée  
            Session::set('user_id', $userId);  
            Session::set('username', $username);  
            // Déterminer is_admin depuis le groupe  
            $isAdmin = \App\Helpers\GroupHelper::isAdmin($userId);  
            Session::set('is_admin', $isAdmin);  
            Session::flash('success', \App\Helpers\Translator::trans('register.success', [], 'auth'));  
            $this->redirect(\App\Helpers\UrlHelper::to('/'));  
        }  
    }  
}
Avatar
Posts 132

re :)

j'ai remplacé le fichier correspondant mais je ne peux toujours pas épingler/résolu.

pour le groupe "Membre/membre", j'ai basculé les utilisateurs sur "membre" mais maintenant, comment je fais pour supprimer le groupe "Membre" ?

edit : j'ai tenté de téléchargé l'archive complète mais le lien "Téléchargement" est inactif.

Edited on Jan 11, 2026 By arpinux .

Avatar
Posts 132

re :)

pour le debug : la fonction debug est activé par défaut (normal) mais est grisée et je ne peux la désactiver. lorsque je me connecte à l'interface d'administration, j'ai un pop-up " Mode debug verrouillé temporairement pour maintenance " alors que je ne suis pas en mode maintenance.

Avatar
Posts 132

re :)

lien de téléchargement fonctionnel, du coup, mise à jour depuis l'archive.

bug épingler/résolu fonctionnel :)

en revanche, mode debug toujours vérrouillé par défaut et non désactivable depuis l'interface d'admin.

Avatar
Posts 132

re :)

pour le groupe "Member", je l'ai tout simplement effacé de /stockage/json/groups.json ;)

Avatar
Posts 132

re :)

un certaine latence est remarquée sur le forum. il faut recharger plusieurs fois la page d'accueil pour voir appara

Avatar
Posts 243

Hello Arpinux, je vois que tu te fais toi-même les questions et réponses ! 😄

1. Mode débogage actif

Concernant le mode débogage restant activé, c'est une décision de ma part. La minification des assets est assez complexe et peut parfois causer des problèmes d'affichage 🖥️. Je travaille dessus pour la prochaine version 🚀.

2. Problème de groupe

Le problème de groupe est maintenant résolu et corrigé dans la version disponible en téléchargement 📥. J’ai également découvert une anomalie qui invalidait les groupes, réinitialisant fréquemment les permissions 🔒, ce qui n'était pas idéal. Cela a également été corrigé ✅.

3. Latence globale du forum

Pour la latence globale du forum sur l'index, je vais affiner la gestion du cache, qui est peut-être un peu trop agressive pour le moment 🕐. Une fois la minification en place et la gestion du cache optimisée, Flatboard sera beaucoup plus réactif ⚡.

4. Conclusion

La base est maintenant solide, il ne reste plus que quelques ajustements à faire en fonction des retours 🛠️.

Donc, pas de panique 😌 !

Avatar
Posts 132

pas de panique de mon côté :)

oki pour le debug par défaut.

je passe en pro quand tu passes en stable :) merci encore pour ton travail et ta réactivité :)

  • Like(1)
    FredFred
Avatar
Posts 132

re :)

un petit bug : dans les paramêtres du profil, section "notifications", si je déselectionne les notifications web, elles reviennent par défaut.

Edited on Jan 11, 2026 By arpinux .

Avatar
Posts 243

arpinux

Archive à jour !
PS: les signature sont aussi disponible au survol des avatars ;)

Edited on Jan 12, 2026 By Fred .

Avatar
Posts 132

cool pour les signatures :) mais il faudrait modifier la description dans les paramêtres du profil car "Votre signature apparaîtra sous vos messages. Markdown supporté. " est spécifié ;)

je chope l'archive dès que le bouton "download" fonctionne ;)

Edited on Jan 12, 2026 By arpinux .

Avatar
Posts 132

archive téléchargée, mise à jour effectuée et oops ... 404 sur la page d'accueil /forum/ :D

bref, j'ai recollé ma sauvegarde. je retente plus tard pour récolter les logs mais là, j'ai pas le temps.

Avatar
Posts 132

re :)

ah bah si, j'ai un peu de temps :)

donc : mise à jour effectuée par écrasement simple, bug : page principale en 404, logs en pj

puis j'ai re-re-collé mon backup pour garder mon forum accessible.

Attachments
logs.zip
13 KBPlease log in to download files.
Avatar
Posts 243

Salut, mise à jour RC10 dispo qui re-corrige cette erreur de route....Et plein d'autres bugs.

Avatar
Posts 132

cool :) je télécharge dès que le bouton est actif ;)

Avatar
Posts 243

Je pige pas ce problème, je viens de faire le test de télécharger l'archive avant de publier justement avant de poster cette mise à jour, tu as quoi une 404 ?

Avatar
Posts 243

Avant que tu me le dise, j'ai corrigé le problème de l'affichage de :root{}, il faut re téléchargé l'archive

This discussion is locked

Log in to reply
navigation.title
22Posts
post #1
10 Jan 2026
ByUtilisateur