sococa Posted August 5 Share Posted August 5 (edited) Theme: Classic Hello everyone, I'm looking to create a module (my first module...) that allows me to have a 2FA login for the front end. I'm at the stage where I would just like to make the connection between a service and the front .tpl located in another module. After several days, I'm still at the same point and don't know where I went wrong. Probably a silly mistake. The module installs fine and the new columns are added to the database. I have created the routes.yml, the controller, and the services, but when I call the URL by clicking the button, I just get a 404 error in the console. Note that I made the files by hand, I'm not sure if I needed to run composer commands? Here is the .tpl code. The problematic URL is "modules/lebruntwofa/sendcode". <div style="display:none;"> <div id="new_login_form"> <div id="img-cust-pop"> </div> <div id="already-customer" class="bgcolor_second text-center"> <form id="login-form-new" action="#" method="post"> <h3 class="color_first">Déjà client ?</h3> <p>Connectez-vous pour accéder à votre compte.</p> <div class="help-block" id="login-form-new-error"> </div> <div> {foreach from=$new_login_form["formFields"] item="field"} {block name='form_field'} {form_field field=$field} {/block} {/foreach} <div class="forgot-password text-right"> <a href="{$urls.pages.password}" rel="nofollow"> {l s='Forgot your password?' d='Shop.Theme.Customeraccount'} </a> </div> <input type="button" name="generate_code" id="generate_code" value="Recevoir mon code" > <input type="text" name="twofa_code" placeholder="Entrez votre code" required> <button type="submit" name="submit_code">Vérifier</button> </div> <footer class="form-footer text-sm-center clearfix"> <input type="hidden" name="submitLogin" value="1"> {block name='form_buttons'} <button id="submit-login-new" class="btn btn-primary" data-link-action="sign-in" type="submit" class="form-control-submit"> {l s='Sign in' d='Shop.Theme.Actions'} </button> {/block} </footer> </form> </div> <div id="new-customer" class="bgcolor_third text-center"> <h3 class="color_first">Nouveau client?</h3> <p>Suivez vos commandes, consultez votre historique d'achat, bénéficiez d'un suivi personnalisé et bien d'autres avantages.</p> <p><a href="{$urls.pages.registration}" class="button-register" rel="nofollow">Créer mon compte</a></p> </div> </div> </div> <script type="text/javascript"> jQuery(document).ready(function() { jQuery("#generate_code").click(function () { let email = jQuery("#field-email").val(); /*console.log(email); OK, l'email de l'input est bien récupéré*/ $.ajax({ type: "POST", url: "/modules/lebruntwofa/sendcode", data: { ajax: true, action: 'sendCode', email: email }, dataType: "json", encode: true, }).done(function (data) { if (data.success) { alert('Code sent successfully.'); } else { alert('Error: ' + data.error); } }); }); jQuery("#login-form-new").submit(function (event) { event.preventDefault(); var formData = { email: jQuery("#field-email").val(), password: jQuery("#field-password").val(), submitLogin: jQuery("input[name='submitLogin']").val(), ajax: true }; $.ajax({ type: "POST", url: "/module/lebruncustpop/login", data: formData, dataType: "json", encode: true, }).done(function (data) { if(data.error.length === 0){ location.reload(); }else{ jQuery("#login-form-new-error").html("<ul><li class='alert alert-danger'>" + data.error + "</li></ul>"); } }); }); jQuery("a.fancybox_login").fancybox({ "type" : "inline", "width":400, "height":600 }); }); </script> I am sharing in a zip file the module I made as well as the tpl where I call the file. I only included the tpl from the second module to be as clear as possible. I hope one of you has the time to help me. Thanks bug_url.zip Edited August 9 by sococa (see edit history) Link to comment Share on other sites More sharing options...
Nickz Posted August 5 Share Posted August 5 do you use seo friendly URLS? Link to comment Share on other sites More sharing options...
Andrei H Posted August 5 Share Posted August 5 Hello, The problem seems to be the fact that you are trying to implement a Front Controller in a Symfony manner. As highlighted in the documentation, you should do that only for the Admin Controllers - https://devdocs.prestashop-project.org/8/modules/concepts/controllers/front-controllers/ If you follow the rules from the 'Creating a front controller' section - https://devdocs.prestashop-project.org/8/modules/concepts/controllers/front-controllers/#creating-a-front-controller, the controller should work as expected. You can also check how the official modules are implementing these controllers - Eg.: https://github.com/PrestaShop/ps_checkpayment Link to comment Share on other sites More sharing options...
sococa Posted August 6 Author Share Posted August 6 Hi, Thanks for your answers @Nickz i'm using "simplified url" @Andrei H Ok, i try to do like that I come back later Link to comment Share on other sites More sharing options...
sococa Posted August 6 Author Share Posted August 6 So this what i changed, without results : 1/ Changed the controller architecture. Now it is in modules/lebruntwofa/controllers/front/sendcode.php and is called class LebruntwofaSendcodeModuleFrontController extends ModuleFrontController 2/ In the main class, add $this->ajax = true; in the initContent(). 3/ Changed _controller: 'Lebrun\Lebruntwofa\Controller\SendCodeController::sendCode' to : _controller: 'Lebrun\Lebruntwofa\Controller\LebruntwofaSendcodeModuleFrontController::sendCode' Could the problem be due to the fact that the URL is called in another module (lebruncustpop)? Also, is there something to do with Composer? A command to run? I also verified my service but it seems good : services: _defaults: public: true lebrun.lebruntwofa.send_code_service: class: Lebrun\Lebruntwofa\Services\SendCodeService <?php namespace Lebrun\Lebruntwofa\Services; use Customer; use DB; class SendCodeService { public function generateAndSendCode($customerId) { generateRandomCode(); sendCodeByMail(); } public function generateRandomCode() { $code = rand(100000, 999999); // Génère un code à 6 chiffres $expiration = date('Y-m-d H:i:s', strtotime('+1 minute')); // Définit l'expiration à 1 minute à partir de maintenant } private function saveCodeToDatabase($customerId, $code, $expiration) { return Db::getInstance()->execute(' UPDATE `' . _DB_PREFIX_ . 'customer` SET twofa_code = ' . (int)$code . ', twofa_code_expiration = "' . pSQL($expiration) . '" WHERE id_customer = ' . (int)$customerId ); } public function sendCodeByMail($customerId, $code, $expiration) { // Charger le client $customer = new Customer($customerId); $customer->twofa_code = $code; $customer->twofa_code_expiration = $expiration; // Sauvegarder le code et son expiration dans la base de données $customer->update(); // Envoyer l'email $subject = 'Your 2FA Code'; $message = 'Your 2FA code is: ' . $code . '. This code will expire in 1 minute.'; mail($customer->email, $subject, $message); } } I share you the module with the corrections lebruntwofa.zip Link to comment Share on other sites More sharing options...
Andrei H Posted August 6 Share Posted August 6 Hello, The code looks good, it just needs a few tweaks on the controller. When it comes down to Front Controllers, I am not sure if you can actually change the URL for it. That is automatically built by PrestaShop and it is similar to: <base_url>/<language>/module/<module_name>/<controller_name> If you plan on commercializing this module, a rule of thumb is to never hardcode the URL in JavaScript, as it can be different for some users. You should generate it in the module and pass it to the client as a JavaScript variable (you can do that with Media::addJsDef and a hook like hookDisplayHeader or hookActionFrontControllerSetMedia) I made the mentioned changes to the controller and also left a commented line in the lebruntwofa.php file on line 32 - uncommenting it and reloading any page will display the actual URL for the controller (once you get the link, you can remove/comment it again). Directly accessing that link will display something like: {"success":true,"message":"Works as expected."} If you want a controller with multiple methods, you will need to add some logic in the postProcess method that will be executed based on the request method or some parameter - this is up to you. Let me know if the above steps helped or if you need some additional clearance. lebruntwofa.zip Link to comment Share on other sites More sharing options...
sococa Posted August 7 Author Share Posted August 7 (edited) Hi @Andrei H, big thanks for your help and explications.the line die(print_r($this->context->link->getModuleLink('lebruntwofa', 'sendcode'))); create an infinty loop : " Xdebug has detected a possible infinite loop, and aborted your script with a stack depth of '512' frames [Error 0] " is it a sign of a bad configuration of my controller ? I didn't success to recup the url :/ i don't know if i search in the rigth direction ... Edited August 7 by sococa (see edit history) Link to comment Share on other sites More sharing options...
Andrei H Posted August 7 Share Posted August 7 (edited) Hello, I haven't tested it with xdebug enabled, my bad. In my local environment it works as expected. Since you are using xdebug, can you set a breakpoint for this specific line? It should highlight it's value. Otherwise, can you try and remove that die? Just have it as: print_r($this->context->link->getModuleLink('lebruntwofa', 'sendcode')); If you go to the module manager page, it should display the link on top of the page. You can also try and access: <base_url>/en/module/lebruntwofa/sendcode - as this is most likely the URL (or /fr/ instead of the /en/) Let me know if this works Edited August 7 by Andrei H (see edit history) Link to comment Share on other sites More sharing options...
sococa Posted August 7 Author Share Posted August 7 (edited) Sorry for the time don't have good control of XDebug and i forgot how it works. So i share you what i see : $this: Lebruntwofa _path"/modules/lebruntwofa/" local_path"/var/www/prestashop/modules/lebruntwofa/" I tried with /var/www/prestashop/modules/lebruntwofa/sendcode in the display_before_body.tpl jQuery("#generate_code").click(function () { let email = jQuery("#field-email").val(); /*console.log(email); OK, l'email de l'input est bien récupéré*/ $.ajax({ type: "POST", url: "/var/www/prestashop/modules/lebruntwofa/sendcode", data: { ajax: true, action: 'sendCode', email: email }, dataType: "json", encode: true, }).done(function (data) { if (data.success) { alert('Code sent successfully.'); } else { alert('Error: ' + data.error); } }); }); But i have a 403 : POST https://prestashop.local/var/www/prestashop/modules/lebruntwofa/sendcode 403 (Forbidden) And also tried to access directly with https://prestashop.local/fr/modules/lebruntwofa/sendcode and other declinations, but 500 error . Just have print_r($this->context->link->getModuleLink('lebruntwofa', 'sendcode')); without die cause too an infinity loop :/ Edited August 7 by sococa (see edit history) Link to comment Share on other sites More sharing options...
Andrei H Posted August 7 Share Posted August 7 (edited) Hello, The AJAX call cannot be made to "/var/www/prestashop/modules/lebruntwofa/sendcode", it will need to be the URL - eg https://prestashop.local/fr/modules/lebruntwofa/sendcode (all request methods like POST and GET should be sent to this URL) As for the 500, that might be due to the 'initContent' method, as it has some invalid code. Can you comment that switch statement, please? It is weird that in my case, the initContent is skipped. What PrestaShop version are you using? Edited August 7 by Andrei H (see edit history) Link to comment Share on other sites More sharing options...
sococa Posted August 7 Author Share Posted August 7 I'm using prestashop 8.1 Good news, i tried again and it's working with this url : https://prestashop.local/module/lebruntwofa/sendcode without the 'fr' or 'en'. I don't know what i did before, cause it's working even with the uncomment switch. Now, after the click on the button, i see the alert 'Code sent successfully' $.ajax({ type: "POST", url: "/module/lebruntwofa/sendcode", data: { ajax: true, action: 'sendCode', email: email }, dataType: "json", encode: true, }).done(function (data) { if (data.success) { alert('Code sent successfully.'); } else { alert('Error: ' + data.error); } }); }); But i don't understand, because my route is with a 's' in 'modules' and that works only without the 's' in the .tpl file lebruntwofa_sendcode: path: /modules/lebruntwofa/sendcode methods: [GET, POST] defaults: _controller: 'Lebrun\Lebruntwofa\Controller\LebruntwofaSendcodeModuleFrontController::sendCode' Link to comment Share on other sites More sharing options...
Andrei H Posted August 7 Share Posted August 7 Hello, Great news! When it comes down to Front Controllers, the link for them is automatically generated by PrestaShop - I am not sure if you can change it in the config file. This is based on the Shop Parameters -> Traffic & SEO -> Route to modules setting. This is why I mentioned you should use the $this->context->link->getModuleLink('lebruntwofa', 'sendcode') method to pass the link to the store, as it can be different based on that setting, but the method will return the correct URL each time. Link to comment Share on other sites More sharing options...
sococa Posted August 7 Author Share Posted August 7 Huge thanks @Andrei H for your help and explications again ... I understand that's clear. Now, i can moving forward on the module. 1 Link to comment Share on other sites More sharing options...
sococa Posted August 9 Author Share Posted August 9 How mark this topic as "solved" please ? Link to comment Share on other sites More sharing options...
Andrei H Posted August 9 Share Posted August 9 Hello, I think you have the option to edit the title. You can also have a look at this link, section [SOLVED] Topic 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now