Prestashop custom module routing issue after update to 1.7.8.4 - prestashop

I just updated a PrestaShop website from 1.7.8.3 to 1.7.8.4, everything worked fine, but I'm havine 404 errors on custom module routes.
On module install I register routes like:
$this->registerHook('ModuleRoutes')
And my routes are like:
public function hookModuleRoutes() {
$urls = array(
'module-mymodulename-posts' => array(
'controller' => 'posts',
'rule' => 'posts/list',
'keywords' => array(),
'params' => array(
'fc' => 'module',
'module' => 'mymodulename',
)
),
...
);
return $urls;
}
Now www.mywebsite.com/posts/list returns 404.
And www.mywebsite.com/modules/mymodulename/posts works but url is not looking as good.
It all was working fine until this morning update.
Any idea on how I could get this solved ?
I have nothing about routing in the release logs.

Apparently a PrestaShop bug:
https://github.com/PrestaShop/PrestaShop/issues/27854
that just got a fix:
https://github.com/PrestaShop/PrestaShop/pull/27874/files
Fix works fine on my side.

You have to change getHookStatusByName function in classes/Hook.php file :
public static function getHookStatusByName($hook_name): bool
{
$hook_names = [];
if (Cache::isStored('active_hooks')) {
$hook_names = Cache::retrieve('active_hooks');
} else {
$sql = new DbQuery();
$sql->select('lower(name) as name');
$sql->from('hook', 'h');
$sql->where('h.active = 1');
$active_hooks = Db::getInstance()->executeS($sql);
if (!empty($active_hooks)) {
$hook_names = array_column($active_hooks, 'name');
if (is_array($hook_names)) {
Cache::store('active_hooks', $hook_names);
}
}
}
return in_array(strtolower($hook_name), $hook_names);
}

Related

Prestashop 1.7.7 - HelperForm in a Multistore Context

I'm testing a first simple version for a Multistore-compatible module. It has just two settings, which have to be saved differently depending on the current shop Context (a single shop mainly).
Now, I know that from 1.7.8 there are additional checkbox for each setting in the BO Form, but I have to manage to get it work also for 1.7.7.
Now, both Configuration::updateValue() and Configuration::get() should be multistore-ready, meaning that they update or retrieve the value only for the current context, so it should be fine.
The weird thing is that, after installing the test module, if I go to the configuration page, it automatically redirects to an All-Shop context and, if I try to manually switch (from the dropdown in the top right), it shows a blank page. Same thing happens if I try to deactivate the bottom checkbox "Activate this module in the context of: all shops".
Here is my code:
class TestModule extends Module
{
public function __construct()
{
$this->name = 'testmodule';
$this->tab = 'front_office_features';
$this->version = '1.0.0';
$this->author = 'Test';
$this->need_instance = 1;
$this->ps_versions_compliancy = [
'min' => '1.7.0.0',
'max' => '1.7.8.0',
];
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l("Test Module");
$this->description = $this->l('Collection of custom test extensions');
$this->confirmUninstall = $this->l('Are you sure you want to uninstall?');
if (!Configuration::get('TESTM_v')) {
$this->warning = $this->l('No version provided');
}
}
public function install()
{
if (Shop::isFeatureActive()) {
Shop::setContext(Shop::CONTEXT_ALL);
}
return (
parent::install()
&& $this->registerHook('header')
&& $this->registerHook('backOfficeHeader')
&& Configuration::updateValue('TESTM_v', $this->version)
);
}
public function uninstall()
{
if (Shop::isFeatureActive()) {
Shop::setContext(Shop::CONTEXT_ALL);
}
return (
parent::uninstall()
&& $this->unregisterHook('header')
&& $this->unregisterHook('backOfficeHeader')
&& Configuration::deleteByName('TESTM_v')
);
}
public function getContent()
{
// this part is executed only when the form is submitted
if (Tools::isSubmit('submit' . $this->name)) {
// retrieve the value set by the user
$configValue1 = (string) Tools::getValue('TESTM_CONFIG_1');
$configValue2 = (string) Tools::getValue('TESTM_CONFIG_2');
// check that the value 1 is valid
if (empty($configValue1)) {
// invalid value, show an error
$output = $this->displayError($this->l('Invalid Configuration value'));
} else {
// value is ok, update it and display a confirmation message
Configuration::updateValue('TESTM_CONFIG_1', $configValue1);
$output = $this->displayConfirmation($this->l('Settings updated'));
}
// check that the value 2 is valid
Configuration::updateValue('TESTM_CONFIG_2', $configValue2);
$output = $this->displayConfirmation($this->l('Settings updated'));
}
// display any message, then the form
return $output . $this->displayForm();
}
public function displayForm()
{
// Init Fields form array
$form = [
'form' => [
'legend' => [
'title' => $this->l('Settings'),
],
'input' => [
[
'type' => 'text',
'label' => $this->l('Custom CSS file-name.'),
'name' => 'TESTM_CONFIG_1',
'size' => 20,
'required' => true,
],
[
'type' => 'switch',
'label' => $this->l('Enable custom CSS loading.'),
'name' => 'TESTM_CONFIG_2',
'is_bool' => true,
'desc' => $this->l('required'),
'values' => array(
array(
'id' => 'sw1_on',
'value' => 1,
'label' => $this->l('Enabled')
),
array(
'id' => 'sw1_off',
'value' => 0,
'label' => $this->l('Disabled')
)
)
],
],
'submit' => [
'title' => $this->l('Save'),
'class' => 'btn btn-default pull-right',
],
],
];
$helper = new HelperForm();
// Module, token and currentIndex
$helper->table = $this->table;
$helper->name_controller = $this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->currentIndex = AdminController::$currentIndex . '&' . http_build_query(['configure' => $this->name]);
$helper->submit_action = 'submit' . $this->name;
// Default language
$helper->default_form_language = (int) Configuration::get('PS_LANG_DEFAULT');
// Load current value into the form or take default
$helper->fields_value['TESTM_CONFIG_1'] = Tools::getValue('TESTM_CONFIG_1', Configuration::get('TESTM_CONFIG_1'));
$helper->fields_value['TESTM_CONFIG_2'] = Tools::getValue('TESTM_CONFIG_2', Configuration::get('TESTM_CONFIG_2'));
return $helper->generateForm([$form]);
}
/**
* Custom CSS & JavaScript Hook for FO
*/
public function hookHeader()
{
//$this->context->controller->addJS($this->_path.'/views/js/front.js');
if (Configuration::get('TESTM_CONFIG_2') == 1) {
$this->context->controller->addCSS($this->_path.'/views/css/'.((string)Configuration::get('TESTM_CONFIG_1')));
} else {
$this->context->controller->removeCSS($this->_path.'/views/css/'.((string)Configuration::get('TESTM_CONFIG_1')));
}
}
}
As you can see it's a pretty simple setting: just load a custom CSS file and choose if loading it or not. I've red official PS Docs per Multistore handling and searched online, but cannot find an answer to this specific problem.
I've also tried to add:
if (Shop::isFeatureActive()) {
$currentIdShop = Shop::getContextShopID();
Shop::setContext(Shop::CONTEXT_SHOP, $currentIdShop);
}
To the 'displayForm()' function, but without results.
Thank you in advance.
It seemsit was a caching error.
After trying many variations, I can confirm that the first solution I've tried was the correct one, meaning that:
if (Shop::isFeatureActive()) {
$currentIdShop = Shop::getContextShopID();
Shop::setContext(Shop::CONTEXT_SHOP, $currentIdShop);
}
needs to be added ad the beginning of the "displayForm()" function for it to work when selecting a single shop. Values are now correctly saved in the database. With a little bit extra logic it can be arranged to behave differently (if needed) when saving for "All shops" context.

Lumen Google reCAPTCHA validation

I already seen some tuts and example about it and I have implemented it somehow.
Method in controller looks like this:
The logic used is just php and I would like to use more a lumen/laravel logic and not just simple vanilla php. Also I have tried and did not worked anhskohbo / no-captcha
public function create(Request $request)
{
try {
$this->validate($request, [
'reference' => 'required|string',
'first_name' => 'required|string|max:50',
'last_name' => 'required|string|max:50',
'birthdate' => 'required|before:today',
'gender' => 'required|string',
'email' => 'required|email|unique:candidates',
'g-recaptcha-response' => 'required',
]);
//Google recaptcha validation
if ($request->has('g-recaptcha-response')) {
$secretAPIkey = env("RECAPTCHA_KEY");
// reCAPTCHA response verification
$verifyResponse = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.$secretAPIkey.'&response='.$request->input('captcha-response'));
$response = json_decode($verifyResponse);
if ($response->success) {
//Form submission
//Saving data from request in candidates
$candidate = Candidate::create($request->except('cv_path'));
$response = array(
"status" => "alert-success",
"message" => "Your mail have been sent."
);
} else {
$response = array(
"status" => "alert-danger",
"message" => "Robot verification failed, please try again."
);
}
}
} catch(Exception $e) {
return response()->json($e->getMessage());
}
return response()->json(['id' => $candidate->id, $response]);
}
Okey. Google has an package for this:reCAPTCHA PHP client library
just: composer require google/recaptcha "^1.2"
and in your method inside controller:
$recaptcha = new \ReCaptcha\ReCaptcha(config('app.captcha.secret_key'));
$response = $recaptcha->verify($request->input('g-recaptcha-response'), $_SERVER['REMOTE_ADDR']);
if ($response->isSuccess()) {
//Your logic goes here
} else {
$errors = $response->getErrorCodes();
}
config('app.captcha.site_key') means that I got the key from from config/app.php and there from .env file.
If you have not config folder, you should create it, also create app.php file same as in laravel.

Phalcon 4 multi module backend not loading

I'm in windows using php-7.4.1 Architecture-x64, phalcon - 4.0.2, psr - 0.7.0 and follow instruction from 'https://docs.phalcon.io/4.0/en/application' but the problem is its always render frontend module & its view. I'm unable to find out what i'm doing wrong?
[Index.php]
use Phalcon\Mvc\Router;
use Phalcon\Mvc\Application;
use Phalcon\Di\FactoryDefault;
$di = new FactoryDefault();
$di->set('router',function () {
$router = new Router(false);
$router->setDefaultModule('frontend');
$router->add('/login',
[
'module' => 'backend',
'controller' => 'index',
'action' => 'index',
]
);
$router->add('/admin/products/:action',
[
'module' => 'backend',
'controller' => 'index',
'action' => 1,
]
);
return $router;
}
);
$application = new Application($di);
$application->registerModules(
[
'frontend' => [
'className' => \Multiple\Frontend\Module::class,
'path' => '../apps/frontend/Module.php',
],
'backend' => [
'className' => \Multiple\Backend\Module::class,
'path' => '../apps/backend/Module.php',
],
]
);
try {
$response = $application->handle($_SERVER["REQUEST_URI"]);
$response->send();
} catch (\Exception $e) {
echo $e->getMessage();
}
[Backend module]
<?php
namespace Multiple\Backend;
use Phalcon\Loader;
use Phalcon\Mvc\View;
use Phalcon\Di\DiInterface;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\ModuleDefinitionInterface;
class Module implements ModuleDefinitionInterface
{
public function registerAutoloaders(DiInterface $di = null)
{
$loader = new Loader();
$loader->registerNamespaces(
[
'Multiple\Backend\Controllers' => '../apps/backend/controllers/',
'Multiple\Backend\Models' => '../apps/backend/models/',
]
);
$loader->register();
}
public function registerServices(DiInterface $di)
{
$di->set('dispatcher',function () {
$dispatcher = new Dispatcher();
$dispatcher->setDefaultNamespace('Multiple\Backend\Controllers');
return $dispatcher;
}
);
$di->set('view',function () {
$view = new View();
$view->setViewsDir('../apps/backend/views/');
return $view;
}
);
}
}
[Index Controller]
<?php
namespace Multiple\Backend\Controllers;
use Phalcon\Mvc\Controller;
class IndexController extends Controller
{
public function indexAction()
{
return '<h1>Back Controller!</h1>';
}
}
Did you set your namespaces in the frontend module as well? Like you did with registerAutoloaders in the backend.
Make sure you have registered your new module in
../app/bootstrap_web.php around line 47 which looks as shown below
$application->registerModules([
'frontend' => ['className' => 'MyApp\Modules\Frontend\Module'],
// <--- add your new module here --->
]);
and that your module class is also registered in the loader at ../app/config/loader.php around line 18 which looks as shown below
$loader->registerClasses([
'MyApp\Modules\Frontend\Module' => APP_PATH . '/modules/frontend/Module.php',
// <--- Add your new module class here --->
]);
Always keep an eye on your namespaces. I hope it helps.

Laravel 5.6 - creation user not working

my application used to working well with registration user but now it dont.
here a portion of my model User
protected $fillable = [
'prenom', 'nom', 'email','photo_path','password',
];
here my validation function :
protected function validator(array $data)
{
return Validator::make($data, [
'prenom' => 'required|string|max:255',
'nom' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'photo_path' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:10000',
'password' => 'required|string|min:6|confirmed',
]);
}
here my create function :
protected function create(array $data)
{
dd($data);
$photoInput = request('photo_path');
$userPhotoPath='users';
$storagePhotoPath = Storage::disk('images')->put($userPhotoPath, $photoInput);
return User::create([
'prenom' => $data['prenom'],
'nom' => $data['nom'],
'email' => $data['email'],
'photo_path' => $storagePhotoPath,
'password' => Hash::make($data['password']),
]);
}
- POST request working ( return 302 ) but return back with input value
- Auth Route are declared in web.php
- Validation working well
but the php interpretor didnt get inside create function...
i just see in debugbar that information :
The given data was invalid./home/e7250/Laravel/ManageMyWorkLife/vendor/laravel/framework/src/Illuminate/Validation/Validator.php#306Illuminate\Validation\ValidationException
public function validate()
{
if ($this->fails()) {
throw new ValidationException($this);
}
$data = collect($this->getData())
but my validation working because i have error message near my InputTexte.
so i dont understand that error message ...
Do you have any clue ?
Well, you need to remove the dd(); function before you run something. Other wise it will end the execution of all other operations.
Check if your User Model has a constructor, if so remove it and check if the problem still accours. This fixed it for me.

yii. can't logout from module

I have admin module and different CWebUser(adminuser) for that module. It works good for login. So I can login in main app and in module by different users. But when I call logout method in module
Yii::app()->getModule('admin')->adminuser->logout();
it log me out from module and from main app as well.
how can I fix it?
thanks beforehand.
I think the key is stateKeyPrefix which can be used to tell different modules to use different session keys.
I will put main config file user section.
'user' => [
'allowAutoLogin' => true,
**'stateKeyPrefix' => 'YOUR-DEFAULT_',**
'loginUrl' => array('/login'),
'class' => 'application.wsi.auth.WSIWebUser',
'authTimeout' => 3600 * 24 // 1 hour
],
I have Admin module and I will put my AdminModule.php for you.
class AdminModule extends \CWebModule
{
public $defaultController = 'index';
public function init()
{
$this->setImport(array(
'admin.components.*',
));
$this->layout = 'main';
\Yii::app()->setComponents(array(
'authManager' => array(
'class' => 'CPhpAuthManager',
'authFile' => \Yii::getPathOfAlias('admin.data.auth') .'php',
'showErrors' => true,
),
'user' => array(
'stateKeyPrefix' => 'admin_',
'loginUrl' => \Yii::app()->createUrl('/admin/index/login'),
'class' => 'AdminWebUser',
'authTimeout' => 3600 * 24 // 1 day
),
), false);
}
}
I have components folder in admin module with AdminWebUser class in it as well.
class AdminWebUser extends \CWebUser {
public function getId() {
return Yii::app ()->user->getState ( 'id' );
}
public function getName() {
return Yii::app ()->user->getState ( 'name' );
}
public function getRole() {
return Yii::app ()->user->getState ( 'role' );
}
public function getEmail() {
return Yii::app ()->user->getState ( 'email' );
}
}
The rest of login and logout controller codes are same.
Hope it helps. If not please let me know.