Skip to content

Commit 0a9614e

Browse files
movements of features from project-base to packages (#3735)
2 parents f1b6b83 + c7cf5cb commit 0a9614e

File tree

116 files changed

+4281
-388
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+4281
-388
lines changed

assets/js/admin/components/Product.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import Register from '../../common/utils/Register';
33
export default class Product {
44
static init ($container) {
55
Product.initializeSideNavigation($container);
6+
Product.initProductVideos($container);
67
}
78

89
static initializeSideNavigation ($container) {
@@ -23,6 +24,28 @@ export default class Product {
2324
});
2425
});
2526
}
27+
28+
static initProductVideos ($container) {
29+
$container.filterAllNodes('.js-videos-collection').on('click', '.js-remove-row', function () {
30+
$(this).parent().parent().remove();
31+
});
32+
33+
$container.filterAllNodes('.js-videos-collection-add-row').on('click', function (event) {
34+
const $collection = $(this).closest('.js-form-group').find('.js-videos-collection');
35+
let index = $collection.data('index');
36+
index++;
37+
let prototype = $collection.data('prototype');
38+
let item = prototype
39+
.replace(/__name__label__/g, index)
40+
.replace(/__name__/g, index);
41+
42+
let $item = $($.parseHTML(item));
43+
44+
$item.data('index', index);
45+
$collection.data('index', index);
46+
$collection.append($item);
47+
});
48+
}
2649
}
2750

2851
(new Register()).registerCallback(Product.init, 'Product.init');
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import Register from '../../common/utils/Register';
2+
3+
(new Register()).registerCallback($container => {
4+
const getCheckedPositionName = function () {
5+
return $('#advert_form_settings_positionName').val();
6+
};
7+
8+
const initAdvertForm = function () {
9+
const positionNamesWithCategoryTree = [
10+
'productListSecondRow'
11+
];
12+
13+
if (positionNamesWithCategoryTree.includes(getCheckedPositionName())) {
14+
$('#advert_form_settings').find('.js-category-tree-form').closest('.form-line').show();
15+
} else {
16+
$('#advert_form_settings').find('.js-category-tree-form').closest('.form-line').hide();
17+
}
18+
};
19+
20+
initAdvertForm();
21+
$('#advert_form_settings_positionName').change(initAdvertForm);
22+
});

assets/js/admin/components/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import './advert';
12
import './AdministratorForm';
23
import './AdvancedSearch';
34
import './AjaxConfirm';

assets/js/admin/validation/form/validationPromoCode.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ export default function validationPromoCode () {
77
callbacks: {
88
validateUniquePromoCode: function () {
99

10+
},
11+
validateUniquePromoCodeByDomain: function () {
12+
// JS validation is not necessary
1013
}
1114
}
1215
});

src/Component/Domain/DomainAwareSecurityHeadersSetter.php

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@
44

55
namespace Shopsys\FrameworkBundle\Component\Domain;
66

7+
use Shopsys\FrameworkBundle\Component\Setting\Setting;
78
use Symfony\Component\HttpKernel\Event\ResponseEvent;
89

910
class DomainAwareSecurityHeadersSetter
1011
{
1112
/**
1213
* @param \Shopsys\FrameworkBundle\Component\Domain\Domain $domain
14+
* @param \Shopsys\FrameworkBundle\Component\Setting\Setting $setting
1315
*/
14-
public function __construct(protected readonly Domain $domain)
15-
{
16+
public function __construct(
17+
protected readonly Domain $domain,
18+
protected readonly Setting $setting,
19+
) {
1620
}
1721

1822
/**
@@ -28,14 +32,7 @@ public function onKernelResponse(ResponseEvent $event): void
2832
return;
2933
}
3034

31-
// Do not allow to external content from non-HTTPS URLs.
32-
// Other security features stays as if CSP was not used:
33-
// - allow inline JavaScript and CSS
34-
// - allow eval() function in JavaScript
35-
// - allow data URLs
36-
$event->getResponse()->headers->set(
37-
'Content-Security-Policy',
38-
"default-src https: 'unsafe-inline' 'unsafe-eval' data:",
39-
);
35+
$cspHeaderValue = $this->setting->get(Setting::CSP_HEADER);
36+
$event->getResponse()->headers->set('Content-Security-Policy', $cspHeaderValue);
4037
}
4138
}

src/Component/Setting/Setting.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class Setting
2828
public const string IMAGE_STRUCTURE_MIGRATED_FOR_PROXY = 'imageStructureMigratedForProxy';
2929
public const string CUSTOMER_USER_DEFAULT_GROUP_ROLE_ID = 'customerUserDefaultGroupRoleId';
3030
public const string FILE_STRUCTURE_MIGRATED_FOR_RELATIONS = 'fileStructureMigratedForRelations';
31+
public const string CSP_HEADER = 'cspHeader';
3132

3233
/**
3334
* @var \Shopsys\FrameworkBundle\Component\Setting\SettingValue[][]
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Shopsys\FrameworkBundle\Controller\Admin;
6+
7+
use Shopsys\FrameworkBundle\Component\Setting\Setting;
8+
use Shopsys\FrameworkBundle\Form\Admin\CspHeaderSetting\CspHeaderSettingFormType;
9+
use Symfony\Component\HttpFoundation\Request;
10+
use Symfony\Component\HttpFoundation\Response;
11+
use Symfony\Component\Routing\Annotation\Route;
12+
13+
class CspHeaderController extends AdminBaseController
14+
{
15+
/**
16+
* @param \Shopsys\FrameworkBundle\Component\Setting\Setting $setting
17+
*/
18+
public function __construct(protected readonly Setting $setting)
19+
{
20+
}
21+
22+
/**
23+
* @param \Symfony\Component\HttpFoundation\Request $request
24+
* @return \Symfony\Component\HttpFoundation\Response
25+
*/
26+
#[Route(path: 'superadmin/csp-header-setting/')]
27+
public function settingAction(Request $request): Response
28+
{
29+
$formData = ['cspHeader' => $this->setting->get(Setting::CSP_HEADER)];
30+
31+
$form = $this->createForm(CspHeaderSettingFormType::class, $formData);
32+
$form->handleRequest($request);
33+
34+
if ($form->isSubmitted() && $form->isValid()) {
35+
$this->setting->set(Setting::CSP_HEADER, $form->getData()['cspHeader']);
36+
$this->addSuccessFlashTwig(t('Content-Security-Policy header has been set.'));
37+
}
38+
39+
return $this->render('@ShopsysFramework/Admin/Content/CspHeader/setting.html.twig', [
40+
'form' => $form->createView(),
41+
]);
42+
}
43+
}

src/Controller/Admin/FlagController.php

Lines changed: 149 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,185 @@
44

55
namespace Shopsys\FrameworkBundle\Controller\Admin;
66

7+
use Shopsys\FrameworkBundle\Component\ConfirmDelete\ConfirmDeleteResponseFactory;
8+
use Shopsys\FrameworkBundle\Component\Domain\Domain;
79
use Shopsys\FrameworkBundle\Component\Router\Security\Annotation\CsrfProtection;
10+
use Shopsys\FrameworkBundle\Form\Admin\Product\Flag\FlagFormType;
11+
use Shopsys\FrameworkBundle\Model\AdminNavigation\BreadcrumbOverrider;
812
use Shopsys\FrameworkBundle\Model\Product\Flag\Exception\FlagNotFoundException;
13+
use Shopsys\FrameworkBundle\Model\Product\Flag\FlagDataFactory;
914
use Shopsys\FrameworkBundle\Model\Product\Flag\FlagFacade;
10-
use Shopsys\FrameworkBundle\Model\Product\Flag\FlagInlineEdit;
15+
use Shopsys\FrameworkBundle\Model\Product\Flag\FlagGridFactory;
16+
use Symfony\Component\HttpFoundation\Request;
17+
use Symfony\Component\HttpFoundation\Response;
1118
use Symfony\Component\Routing\Annotation\Route;
1219

1320
class FlagController extends AdminBaseController
1421
{
1522
/**
1623
* @param \Shopsys\FrameworkBundle\Model\Product\Flag\FlagFacade $flagFacade
17-
* @param \Shopsys\FrameworkBundle\Model\Product\Flag\FlagInlineEdit $flagInlineEdit
24+
* @param \Shopsys\FrameworkBundle\Model\Product\Flag\FlagGridFactory $flagGridFactory
25+
* @param \Shopsys\FrameworkBundle\Component\ConfirmDelete\ConfirmDeleteResponseFactory $confirmDeleteResponseFactory
26+
* @param \Shopsys\FrameworkBundle\Model\AdminNavigation\BreadcrumbOverrider $breadcrumbOverrider
27+
* @param \Shopsys\FrameworkBundle\Model\Product\Flag\FlagDataFactory $flagDataFactory
28+
* @param \Shopsys\FrameworkBundle\Component\Domain\Domain $domain
1829
*/
1930
public function __construct(
2031
protected readonly FlagFacade $flagFacade,
21-
protected readonly FlagInlineEdit $flagInlineEdit,
32+
protected readonly FlagGridFactory $flagGridFactory,
33+
protected readonly ConfirmDeleteResponseFactory $confirmDeleteResponseFactory,
34+
protected readonly BreadcrumbOverrider $breadcrumbOverrider,
35+
protected readonly FlagDataFactory $flagDataFactory,
36+
protected readonly Domain $domain,
2237
) {
2338
}
2439

2540
#[Route(path: '/product/flag/list/')]
2641
public function listAction()
2742
{
28-
$productInlineEdit = $this->flagInlineEdit;
29-
30-
$grid = $productInlineEdit->getGrid();
43+
$grid = $this->flagGridFactory->create();
3144

3245
return $this->render('@ShopsysFramework/Admin/Content/Flag/list.html.twig', [
3346
'gridView' => $grid->createView(),
3447
]);
3548
}
3649

50+
/**
51+
* @param \Symfony\Component\HttpFoundation\Request $request
52+
* @return \Symfony\Component\HttpFoundation\Response
53+
*/
54+
#[Route(path: '/product/flag/new/')]
55+
public function newAction(Request $request): Response
56+
{
57+
$flagData = $this->flagDataFactory->create();
58+
59+
$form = $this->createForm(FlagFormType::class, $flagData, [
60+
'flag' => null,
61+
]);
62+
$form->handleRequest($request);
63+
64+
if ($form->isSubmitted() && $form->isValid()) {
65+
if (!$this->domain->hasAdminAllDomainsEnabled()) {
66+
$this->addErrorFlash(t('Creating a record requires all domains to be enabled as domain-specific fields cannot be empty. If you want to proceed, select all domains in the Domain filter in the header first.'));
67+
68+
return $this->redirectToRoute('admin_flag_new');
69+
}
70+
71+
$flag = $this->flagFacade->create($flagData);
72+
73+
$this
74+
->addSuccessFlashTwig(
75+
t('Flag <strong><a href="{{ url }}">{{ name }}</a></strong> created'),
76+
[
77+
'name' => $flag->getName(),
78+
'url' => $this->generateUrl('admin_flag_edit', ['id' => $flag->getId()]),
79+
],
80+
);
81+
82+
return $this->redirectToRoute('admin_flag_list');
83+
}
84+
85+
if ($form->isSubmitted() && !$form->isValid()) {
86+
$this->addErrorFlashTwig(t('Please check the correctness of all data filled.'));
87+
}
88+
89+
return $this->render('@ShopsysFramework/Admin/Content/Flag/new.html.twig', [
90+
'form' => $form->createView(),
91+
]);
92+
}
93+
94+
/**
95+
* @param \Symfony\Component\HttpFoundation\Request $request
96+
* @param int $id
97+
* @return \Symfony\Component\HttpFoundation\Response
98+
*/
99+
#[Route(path: '/product/flag/edit/{id}', requirements: ['id' => '\d+'])]
100+
public function editAction(Request $request, int $id): Response
101+
{
102+
$flag = $this->flagFacade->getById($id);
103+
$flagData = $this->flagDataFactory->createFromFlag($flag);
104+
105+
$form = $this->createForm(FlagFormType::class, $flagData, [
106+
'flag' => $flag,
107+
]);
108+
$form->handleRequest($request);
109+
110+
if ($form->isSubmitted() && $form->isValid()) {
111+
$this->flagFacade->edit($id, $flagData);
112+
113+
$this
114+
->addSuccessFlashTwig(
115+
t('Flag <strong><a href="{{ url }}">{{ name }}</a></strong> modified'),
116+
[
117+
'name' => $flag->getName(),
118+
'url' => $this->generateUrl('admin_flag_edit', ['id' => $flag->getId()]),
119+
],
120+
);
121+
122+
return $this->redirectToRoute('admin_flag_list');
123+
}
124+
125+
if ($form->isSubmitted() && !$form->isValid()) {
126+
$this->addErrorFlashTwig(t('Please check the correctness of all data filled.'));
127+
}
128+
129+
$this->breadcrumbOverrider->overrideLastItem(t('Editing flag - {{ name }}', ['{{ name }}' => $flag->getName()]));
130+
131+
return $this->render('@ShopsysFramework/Admin/Content/Flag/edit.html.twig', [
132+
'form' => $form->createView(),
133+
'flag' => $flag,
134+
]);
135+
}
136+
137+
/**
138+
* @param int $id
139+
* @return \Symfony\Component\HttpFoundation\Response
140+
*/
141+
#[Route(path: '/product/flag/delete-confirm/{id}', requirements: ['id' => '\d+'])]
142+
public function deleteConfirmAction(int $id): Response
143+
{
144+
try {
145+
$flag = $this->flagFacade->getById($id);
146+
$flagDependencies = $this->flagFacade->getFlagDependencies($flag->getId());
147+
$hasDependency = $flagDependencies->hasPromoCodeDependency || $flagDependencies->hasSeoMixDependency;
148+
149+
if ($hasDependency) {
150+
return $this->render('@ShopsysFramework/Admin/Content/Flag/deleteForbidden.html.twig', [
151+
'hasPromoCodeDependency' => $flagDependencies->hasPromoCodeDependency,
152+
'hasSeoMixDependency' => $flagDependencies->hasSeoMixDependency,
153+
]);
154+
}
155+
$message = t('Do you really want to remove this flag?');
156+
157+
return $this->confirmDeleteResponseFactory->createDeleteResponse(
158+
$message,
159+
'admin_flag_delete',
160+
$id,
161+
);
162+
} catch (FlagNotFoundException $ex) {
163+
return new Response(t('Selected flag doesn\'t exist.'));
164+
}
165+
}
166+
37167
/**
38168
* @CsrfProtection
39169
* @param int $id
170+
* @return \Symfony\Component\HttpFoundation\Response
40171
*/
41172
#[Route(path: '/product/flag/delete/{id}', requirements: ['id' => '\d+'])]
42-
public function deleteAction($id)
173+
public function deleteAction($id): Response
43174
{
44175
try {
45-
$fullName = $this->flagFacade->getById($id)->getName();
176+
$flag = $this->flagFacade->getById($id);
177+
$fullName = $flag->getName();
178+
179+
$flagDependencies = $this->flagFacade->getFlagDependencies($flag->getId());
180+
181+
if ($flagDependencies->hasSeoMixDependency || $flagDependencies->hasPromoCodeDependency) {
182+
$this->addErrorFlash(t('The selected flag cannot be deleted.'));
183+
184+
return $this->redirectToRoute('admin_flag_list');
185+
}
46186

47187
$this->flagFacade->deleteById($id);
48188

@@ -52,7 +192,7 @@ public function deleteAction($id)
52192
'name' => $fullName,
53193
],
54194
);
55-
} catch (FlagNotFoundException $ex) {
195+
} catch (FlagNotFoundException) {
56196
$this->addErrorFlash(t('Selected flag doesn\'t exist.'));
57197
}
58198

0 commit comments

Comments
 (0)