Jump to content

[SOLVED] 404 error from url to other module


Recommended Posts

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 by sococa (see edit history)
Link to comment
Share on other sites

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

 

 

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

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

Posted (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 by sococa (see edit history)
Link to comment
Share on other sites

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 by Andrei H (see edit history)
Link to comment
Share on other sites

Posted (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 by sococa (see edit history)
Link to comment
Share on other sites

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 by Andrei H (see edit history)
Link to comment
Share on other sites

I'm using prestashop 8.1 Capturedcrandu2024-08-0713-56-36.thumb.png.a0cba66696d4f3d2910a5096d67168d7.png

 

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

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

  • sococa changed the title to [SOLVED] 404 error from url to other module

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...