Skip to content

Commit 0c2ee38

Browse files
authored
Merge pull request #501 from TeamEver/codex/add-advent-calendar-module-for-christmas
feat: add configurable advent calendar block
2 parents 2122475 + 83b57ca commit 0c2ee38

File tree

6 files changed

+1300
-0
lines changed

6 files changed

+1300
-0
lines changed

config/allowed_files.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
'controllers/admin/AdminEverBlockHookController.php',
3737
'controllers/admin/AdminEverBlockShortcodeController.php',
3838
'controllers/admin/index.php',
39+
'controllers/front/advent.php',
3940
'controllers/front/contact.php',
4041
'controllers/front/cron.php',
4142
'controllers/front/everlogin.php',
@@ -257,6 +258,7 @@
257258
'views/templates/hook/prettyblocks/prettyblock_toc.tpl',
258259
'views/templates/hook/prettyblocks/prettyblock_video_products.tpl',
259260
'views/templates/hook/prettyblocks/prettyblock_video_gallery.tpl',
261+
'views/templates/hook/prettyblocks/prettyblock_advent_calendar.tpl',
260262
'views/templates/hook/prettyblocks/prettyblock_scratch_card.tpl',
261263
'views/templates/hook/prettyblocks/prettyblock_wheel_of_fortune.tpl',
262264
'views/templates/hook/prettyblocks/prettyblocks.tpl',

controllers/front/advent.php

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
<?php
2+
/**
3+
* 2019-2025 Team Ever
4+
*
5+
* NOTICE OF LICENSE
6+
*
7+
* This source file is subject to the Academic Free License (AFL 3.0)
8+
* that is bundled with this package in the file LICENSE.txt.
9+
* It is also available through the world-wide-web at this URL:
10+
* http://opensource.org/licenses/afl-3.0.php
11+
* If you did not receive a copy of the license and are unable to
12+
* obtain it through the world-wide-web, please send an email
13+
* to [email protected] so we can send you a copy immediately.
14+
*
15+
* @author Team Ever <https://www.team-ever.com/>
16+
* @copyright 2019-2025 Team Ever
17+
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
18+
*/
19+
20+
if (!defined('_PS_VERSION_')) {
21+
exit;
22+
}
23+
24+
class EverblockAdventModuleFrontController extends ModuleFrontController
25+
{
26+
public function initContent()
27+
{
28+
$this->ajax = true;
29+
parent::initContent();
30+
31+
header('Content-Type: application/json');
32+
33+
$token = Tools::getValue('token');
34+
if (!$token || $token !== Tools::getToken(false)) {
35+
$this->renderJson([
36+
'status' => false,
37+
'message' => $this->module->l('Invalid token', 'advent'),
38+
]);
39+
}
40+
41+
if (!$this->context->customer->isLogged()) {
42+
$this->renderJson([
43+
'status' => false,
44+
'message' => $this->module->l('You must be logged in to open this window.', 'advent'),
45+
]);
46+
}
47+
48+
$idBlock = (int) Tools::getValue('id_block');
49+
$requestedDay = (int) Tools::getValue('day');
50+
if ($idBlock <= 0 || $requestedDay < 1 || $requestedDay > 24) {
51+
$this->renderJson([
52+
'status' => false,
53+
'message' => $this->module->l('Invalid calendar configuration.', 'advent'),
54+
]);
55+
}
56+
57+
$idCustomer = (int) $this->context->customer->id;
58+
$idShop = (int) $this->context->shop->id;
59+
$idLang = (int) $this->context->language->id;
60+
61+
$row = Db::getInstance()->getRow(
62+
'SELECT config, state FROM ' . _DB_PREFIX_ . 'prettyblocks WHERE id_prettyblocks = ' . (int) $idBlock
63+
. ' AND id_shop = ' . (int) $idShop . ' AND id_lang = ' . (int) $idLang
64+
);
65+
66+
if (!$row) {
67+
$this->renderJson([
68+
'status' => false,
69+
'message' => $this->module->l('Configuration not found', 'advent'),
70+
]);
71+
}
72+
73+
$settings = json_decode($row['config'], true);
74+
if (!is_array($settings)) {
75+
$settings = [];
76+
}
77+
78+
$rawWindows = json_decode($row['state'], true);
79+
if (!is_array($rawWindows)) {
80+
$rawWindows = [];
81+
}
82+
83+
$calendarSettings = $this->resolveCalendarSettings($settings);
84+
$window = $this->findWindowForDay($rawWindows, $requestedDay, $idLang);
85+
86+
if (!$window) {
87+
$this->renderJson([
88+
'status' => false,
89+
'message' => $this->module->l('This window is not configured yet.', 'advent'),
90+
]);
91+
}
92+
93+
$today = $this->getNowDate();
94+
$startDate = $calendarSettings['start_date'];
95+
if (!$startDate) {
96+
$startDate = new DateTime('first day of December ' . (int) $today->format('Y'));
97+
}
98+
99+
$windowDate = clone $startDate;
100+
$windowDate->modify('+' . ($requestedDay - 1) . ' days');
101+
102+
if ($today < $windowDate) {
103+
$this->renderJson([
104+
'status' => false,
105+
'message' => sprintf(
106+
$this->module->l('This window will open on %s.', 'advent'),
107+
Tools::displayDate($windowDate->format('Y-m-d'), null, false)
108+
),
109+
'reason' => 'too_early',
110+
'available_on' => $windowDate->format('Y-m-d'),
111+
]);
112+
}
113+
114+
if ($calendarSettings['restrict_to_current_day'] && $today->format('Y-m-d') !== $windowDate->format('Y-m-d')) {
115+
$this->renderJson([
116+
'status' => false,
117+
'message' => $this->module->l('You can only open today\'s window.', 'advent'),
118+
'reason' => 'not_today',
119+
'available_on' => $windowDate->format('Y-m-d'),
120+
]);
121+
}
122+
123+
$ipAddress = Tools::getRemoteAddr();
124+
if (!is_string($ipAddress)) {
125+
$ipAddress = '';
126+
} else {
127+
$ipAddress = Tools::substr($ipAddress, 0, 45);
128+
}
129+
130+
if (!$this->isAdmin()) {
131+
$alreadyCustomer = (bool) Db::getInstance()->getValue(
132+
'SELECT id_everblock_game_play FROM ' . _DB_PREFIX_ . 'everblock_game_play WHERE id_prettyblocks = ' . (int) $idBlock
133+
. ' AND id_customer = ' . (int) $idCustomer
134+
. " AND result = '" . pSQL('day-' . $requestedDay) . "'"
135+
);
136+
137+
$alreadyIp = false;
138+
if ($ipAddress !== '') {
139+
$alreadyIp = (bool) Db::getInstance()->getValue(
140+
'SELECT id_everblock_game_play FROM ' . _DB_PREFIX_ . 'everblock_game_play WHERE id_prettyblocks = ' . (int) $idBlock
141+
. " AND ip_address = '" . pSQL($ipAddress) . "'"
142+
. " AND result = '" . pSQL('day-' . $requestedDay) . "'"
143+
);
144+
}
145+
146+
if ($alreadyCustomer || $alreadyIp) {
147+
$this->renderJson([
148+
'status' => false,
149+
'message' => $this->module->l('You have already opened this window.', 'advent'),
150+
'reason' => 'already_opened',
151+
]);
152+
}
153+
}
154+
155+
Db::getInstance()->insert('everblock_game_play', [
156+
'id_prettyblocks' => (int) $idBlock,
157+
'id_customer' => (int) $idCustomer,
158+
'ip_address' => pSQL($ipAddress),
159+
'result' => pSQL('day-' . $requestedDay),
160+
'is_winner' => 0,
161+
'date_add' => date('Y-m-d H:i:s'),
162+
]);
163+
164+
$this->renderJson([
165+
'status' => true,
166+
'day' => $requestedDay,
167+
'message' => $this->module->l('Window unlocked!', 'advent'),
168+
]);
169+
}
170+
171+
private function renderJson(array $payload)
172+
{
173+
die(json_encode($payload));
174+
}
175+
176+
private function resolveCalendarSettings(array $settings)
177+
{
178+
$restrict = true;
179+
if (array_key_exists('restrict_to_current_day', $settings)) {
180+
$restrictValue = $this->resolveConfigValue($settings['restrict_to_current_day']);
181+
if ($restrictValue !== null) {
182+
$restrict = (bool) $restrictValue;
183+
}
184+
}
185+
186+
$startDate = null;
187+
if (array_key_exists('start_date', $settings)) {
188+
$startRaw = $this->resolveConfigValue($settings['start_date']);
189+
if (is_string($startRaw) && trim($startRaw) !== '') {
190+
$parsed = $this->createDateTime($startRaw);
191+
if ($parsed) {
192+
$startDate = $parsed;
193+
}
194+
}
195+
}
196+
197+
return [
198+
'restrict_to_current_day' => $restrict,
199+
'start_date' => $startDate,
200+
];
201+
}
202+
203+
private function resolveConfigValue($value)
204+
{
205+
if (is_array($value)) {
206+
if (array_key_exists('value', $value)) {
207+
return $this->resolveConfigValue($value['value']);
208+
}
209+
if (array_key_exists($this->context->language->id, $value)) {
210+
return $this->resolveConfigValue($value[$this->context->language->id]);
211+
}
212+
$first = reset($value);
213+
if ($first !== false) {
214+
return $this->resolveConfigValue($first);
215+
}
216+
217+
return null;
218+
}
219+
220+
if (is_scalar($value)) {
221+
return $value;
222+
}
223+
224+
return null;
225+
}
226+
227+
private function findWindowForDay(array $windows, $day, $idLang)
228+
{
229+
foreach ($windows as $window) {
230+
if (!is_array($window)) {
231+
continue;
232+
}
233+
$normalized = $this->normalizeWindow($window, $idLang);
234+
if ((int) ($normalized['day_number'] ?? 0) === (int) $day) {
235+
return $normalized;
236+
}
237+
}
238+
239+
return null;
240+
}
241+
242+
private function normalizeWindow(array $window, $idLang)
243+
{
244+
$normalized = [];
245+
foreach ($window as $key => $value) {
246+
$normalized[$key] = $this->normalizeWindowValue($value, $idLang);
247+
}
248+
249+
return $normalized;
250+
}
251+
252+
private function normalizeWindowValue($value, $idLang)
253+
{
254+
if (is_array($value)) {
255+
if (array_key_exists('value', $value)) {
256+
return $this->normalizeWindowValue($value['value'], $idLang);
257+
}
258+
if (array_key_exists($idLang, $value)) {
259+
return $this->normalizeWindowValue($value[$idLang], $idLang);
260+
}
261+
foreach ($value as $subKey => $subValue) {
262+
$value[$subKey] = $this->normalizeWindowValue($subValue, $idLang);
263+
}
264+
}
265+
266+
return $value;
267+
}
268+
269+
private function createDateTime($value)
270+
{
271+
try {
272+
return new DateTime($value);
273+
} catch (Exception $e) {
274+
return null;
275+
}
276+
}
277+
278+
private function getNowDate()
279+
{
280+
try {
281+
$timezone = new DateTimeZone(@date_default_timezone_get());
282+
} catch (Exception $e) {
283+
$timezone = null;
284+
}
285+
286+
if ($timezone) {
287+
return new DateTime('now', $timezone);
288+
}
289+
290+
return new DateTime();
291+
}
292+
293+
private function isAdmin()
294+
{
295+
return !empty((new Cookie('psAdmin'))->id_employee);
296+
}
297+
}

0 commit comments

Comments
 (0)