Skip to content

Commit

Permalink
Merge branch 'develop' into dependabot/npm_and_yarn/tests/UI/develop/…
Browse files Browse the repository at this point in the history
…types/chai-4.3.6
  • Loading branch information
nesrineabdmouleh committed Sep 12, 2023
2 parents 29e5279 + 77ffff5 commit 3d11fc1
Show file tree
Hide file tree
Showing 89 changed files with 1,693 additions and 1,423 deletions.
1 change: 1 addition & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Expand Up @@ -19,6 +19,7 @@ https://devdocs.prestashop-project.org/8/contribute/contribution-guidelines/pull
| BC breaks? | yes / no
| Deprecations? | yes / no
| How to test? | Indicate how to verify that this change works as expected.
| UI Tests | Please run UI tests and paste here the link to the run. [Read this page to know why and how to use this tool.](https://devdocs.prestashop-project.org/8/contribute/contribution-guidelines/ui-tests/).
| Fixed issue or discussion? | Fixes #{issue number here}, Fixes #{another issue number here}, Fixes https://github.com/PrestaShop/PrestaShop/discussions/ {discussion number here}
| Related PRs | If theme, autoupgrade or other module change is needed to make this change work, provide a link to related PRs here.
| Sponsor company | Your company or customer's name goes here (if applicable).
14 changes: 14 additions & 0 deletions admin-dev/themes/default/scss/partials/_content.scss
Expand Up @@ -383,3 +383,17 @@ body.display-modal {
}
}
}

div[data-role="search-panels"] {
.panel {
a[target="_blank"]::after {
position: relative;
top: 2px;
left: 10px;
font-family: "Material Icons", sans-serif;
color: #bbcdd2;
content: "\e89e";
opacity: 0.7;
}
}
}
Expand Up @@ -155,7 +155,7 @@ $(function() {
<div class="col-lg-{if $searchPanels|@count <= 2}6{else}4{/if}">
<div class="panel">
<h3>{$searchPanel.title}</h3>
<a href="{$searchPanel.link}" class="btn btn-default _blank">{$searchPanel.button_label}</a>
<a href="{$searchPanel.link}" class="btn btn-default{if !isset($searchPanel.same_page) || true !== $searchPanel.same_page} _blank{/if}">{$searchPanel.button_label}</a>
</div>
</div>
{/foreach}
Expand Down
Expand Up @@ -73,7 +73,13 @@ export default class CreateProductModal {
}

if (dataAttributes.productId) {
const editUrl = this.router.generate('admin_products_edit', {productId: dataAttributes.productId});
// The parameter forceDefaultActive must be passed down in the redirect URL or it will be ignored, it was passed via data attributes
// for this purpose only
const editUrl = this.router.generate('admin_products_edit', {
productId: dataAttributes.productId,
forceDefaultActive: dataAttributes.forceDefaultActive ? 1 : 0,
});

// Keep showing loading until the page is refreshed
iframeModal.showLoading();
window.location.href = editUrl;
Expand Down
Expand Up @@ -90,18 +90,27 @@ export default class ProductSEOManager {
},
});

// On reset button click we regenerate the friendly url for currently selected locale
const resetLinkRewriteBtn = document.querySelector<HTMLButtonElement>(ProductMap.seo.resetLinkRewriteBtn)!;
resetLinkRewriteBtn.addEventListener('click', () => this.resetLinkRewrite());

// Disable or enable reset button depending on the name input value at init, on language change and on keyup inputs
// Disable or enable reset button depending on the name input value at init, on language change and on keyup inputs (on name and url inputs)
this.linkRewriteStateRefresh();
this.eventEmitter.on('languageSelected', () => this.linkRewriteStateRefresh());
this.initCallbackOnInputChange(ProductMap.productLocalizedNameInput, () => this.linkRewriteStateRefresh());
this.initCallbackOnInputChange(ProductMap.productLocalizedLinkRewriteInput, () => this.linkRewriteStateRefresh());

const linkRewriteInputs = document.querySelectorAll(`${ProductMap.productLocalizedLinkRewriteInput}`);
if (resetLinkRewriteBtn.dataset.automaticChange === '1') {
this.initCallbackOnInputChange(ProductMap.productLocalizedNameInput, () => this.resetAllLinkRewrites());
}
}

private initCallbackOnInputChange(inputSelector: string, callback: EventListenerOrEventListenerObject): void {
const inputs = document.querySelectorAll(inputSelector);

if (linkRewriteInputs) {
for (let i = 0; i < linkRewriteInputs.length; i += 1) {
linkRewriteInputs[i].addEventListener('keyup', () => this.linkRewriteStateRefresh());
if (inputs) {
for (let i = 0; i < inputs.length; i += 1) {
inputs[i].addEventListener('keyup', callback);
}
}
}
Expand Down Expand Up @@ -138,8 +147,32 @@ export default class ProductSEOManager {
return;
}

this.updateUrlInput(linkRewriteInput, nameValue);
resetLinkRewriteBtn.disabled = true;
}

private updateUrlInput(linkRewriteInput: HTMLInputElement, nameValue: string): void {
// eslint-disable-next-line no-param-reassign
linkRewriteInput.value = window.str2url(nameValue);
linkRewriteInput.dispatchEvent(new Event('change', {bubbles: true}));
resetLinkRewriteBtn.disabled = true;
}

private resetAllLinkRewrites(): void {
const nameInputs = document.querySelectorAll<HTMLInputElement>(ProductMap.productLocalizedNameInput);
nameInputs.forEach((nameInput: HTMLInputElement) => {
nameInput.parentElement?.classList?.forEach((parentClass:string) => {
// Search for class mapping js-locale-en, js-locale-fr, ...
if (parentClass.match(/^js-locale-[a-zA-Z]{2}$/)) {
const linkRewriteSelector = `.${parentClass} ${ProductMap.productLocalizedLinkRewriteInput}`;
const linkRewriteInput = document.querySelector<HTMLInputElement>(linkRewriteSelector);

if (linkRewriteInput) {
this.updateUrlInput(linkRewriteInput, nameInput.value);
}
}
});
});

this.linkRewriteStateRefresh();
}
}
105 changes: 85 additions & 20 deletions classes/Dispatcher.php
Expand Up @@ -576,13 +576,31 @@ private function buildRequestUri($requestUri, $isMultiLanguageActivated, Shop $s
*/
protected function loadRoutes($id_shop = null)
{
// Initialize shop context if not provided
$context = Context::getContext();

if (isset($context->shop) && $id_shop === null) {
$id_shop = (int) $context->shop->id;
}

// Load custom routes from modules
// Initialize language list we will be building our routes in
$language_ids = Language::getIDs();
if (isset($context->language) && !in_array($context->language->id, $language_ids)) {
$language_ids[] = (int) $context->language->id;
}

/*
* Step 1 - We have some default hardcoded routes initialized in $this->default_routes, these will
* be used as a base.
*/

/*
* Step 2 - Module routes
*
* Loads custom routes from modules for given shop. Beware that these routes are not multilanguage,
* passed routes will be the same for each language of the shop.
*
* Module routes can overwrite those set in $this->default_routes, if their name matches.
*/
$modules_routes = Hook::exec('moduleRoutes', ['id_shop' => $id_shop], null, true, false);
if (is_array($modules_routes) && count($modules_routes)) {
foreach ($modules_routes as $module_route) {
Expand All @@ -603,13 +621,13 @@ protected function loadRoutes($id_shop = null)
}
}

$language_ids = Language::getIDs();

if (isset($context->language) && !in_array($context->language->id, $language_ids)) {
$language_ids[] = (int) $context->language->id;
}

// Set default routes
/*
* Step 3 - Initialize default routes into $this->routes that will get used.
*
* This takes each default route we have until now and calls computeRoute upon each route.
* This enriches the route by a final regex and strips not needed keywords. Then, we add it
* to route list of each language.
*/
foreach ($this->default_routes as $id => $route) {
$route = $this->computeRoute(
$route['rule'],
Expand All @@ -618,14 +636,15 @@ protected function loadRoutes($id_shop = null)
isset($route['params']) ? $route['params'] : []
);
foreach ($language_ids as $id_lang) {
// the default routes are the same, whatever the language
$this->routes[$id_shop][$id_lang][$id] = $route;
}
}

// Load the custom routes prior the defaults to avoid infinite loops
if ($this->use_routes) {
// Load routes from meta table
/*
* Step 4 - Load multilanguage routes from meta table. These are static routes for pages like /bestsellers that configurable
* in SEO & URL section in the backoffice and don't use any parameters or keywords.
*/
$sql = 'SELECT m.page, ml.url_rewrite, ml.id_lang
FROM `' . _DB_PREFIX_ . 'meta` m
LEFT JOIN `' . _DB_PREFIX_ . 'meta_lang` ml ON (m.id_meta = ml.id_meta' . Shop::addSqlRestrictionOnLang('ml', (int) $id_shop) . ')
Expand All @@ -646,7 +665,8 @@ protected function loadRoutes($id_shop = null)
}
}

// Set default empty route if no empty route (that's weird I know)
// Set default empty route if no empty route (that's weird I know).
// Should probably be set as default value in the constructor in 9.0.0.
if (!$this->empty_route) {
$this->empty_route = [
'routeID' => 'index',
Expand All @@ -655,26 +675,35 @@ protected function loadRoutes($id_shop = null)
];
}

// Load custom routes
/*
* Step 5 - Custom routes set in ps_configurations. Those are configured product, category,
* cms etc. rules that you can configure in SEO & URL section in the backoffice.
*
* Beware that these routes are not multilanguage, they will be the same for each language of the shop.
* It probably would not be difficult to make them multilanguage, if route was stored in configuration
* for each language.
*/
foreach ($this->default_routes as $route_id => $route_data) {
if ($custom_route = Configuration::get('PS_ROUTE_' . $route_id, null, null, $id_shop)) {
if (isset($context->language) && !in_array($context->language->id, $language_ids)) {
$language_ids[] = (int) $context->language->id;
}

$route = $this->computeRoute(
$custom_route,
$route_data['controller'],
$route_data['keywords'],
isset($route_data['params']) ? $route_data['params'] : []
);
foreach ($language_ids as $id_lang) {
// those routes are the same, whatever the language
$this->routes[$id_shop][$id_lang][$route_id] = $route;
}
}
}
}

/*
* Step 6 - Allow modules to modify routes in any way or add their own multilanguage routes.
*
* Use getRoutes, addRoute, removeRoute methods for this purpose.
*/
Hook::exec('actionAfterLoadRoutes', ['dispatcher' => $this]);
}

/**
Expand Down Expand Up @@ -747,7 +776,9 @@ public function computeRoute($rule, $controller, array $keywords = [], array $pa
}

/**
* @param string $route_id Name of the route (need to be uniq,a second route with same name will override the first)
* Adds a new route to the list of routes. If it already exists, it will override the existing one.
*
* @param string $route_id Name of the route
* @param string $rule Url rule
* @param string $controller Controller to call if request uri match the rule
* @param int $id_lang
Expand Down Expand Up @@ -786,6 +817,40 @@ public function addRoute(
$this->routes[$id_shop][$id_lang][$route_id] = $route;
}

/**
* Returns a list of processed routes getting used.
*
* @return array List of routes
*/
public function getRoutes()
{
return $this->routes;
}

/**
* Removes a route from a list of processed routes.
*
* @param string $route_id Name of the route
* @param int $id_lang
* @param int $id_shop
*/
public function removeRoute($route_id, $id_lang = null, $id_shop = null)
{
$context = Context::getContext();

if (isset($context->language) && $id_lang === null) {
$id_lang = (int) $context->language->id;
}

if (isset($context->shop) && $id_shop === null) {
$id_shop = (int) $context->shop->id;
}

if (isset($this->routes[$id_shop][$id_lang][$route_id])) {
unset($this->routes[$id_shop][$id_lang][$route_id]);
}
}

/**
* Check if a route exists.
*
Expand Down
72 changes: 70 additions & 2 deletions classes/Employee.php
Expand Up @@ -27,12 +27,13 @@
use PrestaShop\PrestaShop\Adapter\ServiceLocator;
use PrestaShop\PrestaShop\Adapter\SymfonyContainer;
use PrestaShop\PrestaShop\Core\Crypto\Hashing;
use PrestaShop\PrestaShop\Core\Model\EmployeeInterface;
use PrestaShopBundle\Security\Admin\SessionRenewer;

/**
* Class EmployeeCore.
*/
class EmployeeCore extends ObjectModel
class EmployeeCore extends ObjectModel implements EmployeeInterface
{
/** @var int|null Employee ID */
public $id;
Expand Down Expand Up @@ -561,7 +562,7 @@ public function hasAuthOnShopGroup($idShopGroup)
*
* @since 1.5.0
*/
public function getDefaultShopID()
public function getDefaultShopID(): int
{
if ($this->isSuperAdmin() || in_array(Configuration::get('PS_SHOP_DEFAULT'), $this->associated_shops)) {
return (int) Configuration::get('PS_SHOP_DEFAULT');
Expand Down Expand Up @@ -761,4 +762,71 @@ public function getDefaultTabClassName()

return null;
}

/*
* Interface functions
*/
public function getId(): int
{
return (int) $this->id;
}

public function getProfileId(): int
{
return (int) $this->id_profile;
}

public function getLanguageId(): int
{
return (int) $this->id_lang;
}

public function getFirstName(): string
{
return $this->firstname;
}

public function getLastName(): string
{
return $this->lastname;
}

public function getEmail(): string
{
return $this->email;
}

public function getPassword(): string
{
return $this->passwd;
}

public function getDefaultTabId(): int
{
return (int) $this->default_tab;
}

public function getAssociatedShopIds(): array
{
return $this->associated_shops;
}

public function getAssociatedShopGroupIds(): array
{
$associatedShopGroupIds = [];
foreach ($this->associated_shops as $shopId) {
/** @var int $groupFromShop */
$groupFromShop = Shop::getGroupFromShop($shopId, true);
if (!empty($groupFromShop) && !in_array($groupFromShop, $associatedShopGroupIds)) {
$associatedShopGroupIds[] = (int) $groupFromShop;
}
}

return $this->associated_shops;
}

public function getImageUrl(): string
{
return $this->getImage();
}
}

0 comments on commit 3d11fc1

Please sign in to comment.