Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
eaa956b
[IMPROVES] Differ loading for main page dashboard + opti visits metrics
Teyir Jan 31, 2025
1ffeca4
[IMPROVES] Add subcategory for Users settings (general, security, bla…
Teyir Feb 3, 2025
136f435
[FIX] Infinite loading in installer
Zomblard Feb 27, 2025
3440b20
[ADD] Send email when logged in
Zomblard Feb 27, 2025
784fce2
[ADD] Global JS constant - Editor no converted files upload
Zomblard Feb 28, 2025
a22e5f5
[REMOVE] debug test
Zomblard Mar 6, 2025
c2683d6
[FIX] User Login send notification
Zomblard Mar 10, 2025
d4f583b
[IMPROVE] Auto select default role
Zomblard Mar 10, 2025
4a46501
[FIX] Modal position
Zomblard Mar 11, 2025
387ff2c
[FIX] Infinite loading in installer
Zomblard Feb 27, 2025
9b7c4b7
[ADD] Send email when logged in
Zomblard Feb 27, 2025
1ec6589
[ADD] Global JS constant - Editor no converted files upload
Zomblard Feb 28, 2025
ece1e1d
[REMOVE] debug test
Zomblard Mar 6, 2025
7ce3fc1
[FIX] User Login send notification
Zomblard Mar 10, 2025
d06ba40
[IMPROVE] Auto select default role
Zomblard Mar 10, 2025
44570a1
[FIX] Modal position
Zomblard Mar 11, 2025
37b2e6a
[FIX] Dockerfile (GD lib)
Teyir Mar 12, 2025
b46e312
[IMPROVES] Update user profile picture
Teyir Mar 12, 2025
fed1fae
[GEN-162][IMPROVES] Users settings - send email when user is logged (…
Teyir Mar 12, 2025
af1805a
[IMPROVES] Add Event Listener '*' wildcard for listening all the events.
Teyir Mar 13, 2025
3c25396
[FIX] Users update password alert
Teyir Mar 14, 2025
952fda9
[FIX] UserProfile update with password + update cache on profile update
Teyir Mar 14, 2025
1bec380
[IMPROVES] AbstractEntity + Add EntityType attribute (useful for enti…
Teyir Mar 20, 2025
04083c7
[IMPROVES] Update delete account slug. (/account/delete/:id)
Teyir Mar 20, 2025
5703da2
[FIX] Fix potential exploit with login
Teyir Mar 20, 2025
7710965
[FIX] Webp upload with exotic color palette
Teyir Mar 22, 2025
c7029f5
[IMPROVES] Deny access to Docker files in .htaccess
Teyir Mar 27, 2025
afedc55
[FIX] Installer toaster error translation
Teyir Mar 27, 2025
2bccfec
[FIX] Redirect::redirectToAdmin
Teyir Mar 29, 2025
ebbf18d
[IMPROVES] Pages package.
Teyir Mar 29, 2025
39e250c
[IMPROVES] Pages package 1.1.0. (#414)
Teyir Mar 29, 2025
f0e65fc
[IMPROVES] Update oAuth Discord logo
Teyir Mar 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,5 @@ __MACOSX/
/composer.json

# Ignore node_modules files and folder
/node_modules/
**/node_modules/
package-lock.json
6 changes: 6 additions & 0 deletions .htaccess
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@
Require all denied
</Files>

# Deny access to docker files
<FilesMatch "Dockerfile|compose\.yaml|\.dockerignore|README.Docker\.md">
Order allow,deny
Deny from all
</FilesMatch>

#Cache images / scripts
<IfModule mod_expires.c>
ExpiresActive on
Expand Down
2 changes: 1 addition & 1 deletion Admin/Resources/Assets/Css/style.css

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions Admin/Resources/Views/template.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use CMW\Manager\Views\View;
use CMW\Utils\Website;

include_once ('Includes/head.inc.php');

Expand All @@ -20,5 +21,11 @@
View::loadInclude($includes, 'afterScript');
?>

<script>
//Variables global utilisable dans les script JS (admin only)
const BASE_URL = "<?= Website::getUrl() ?>";
const WEBSITE_NAME = "<?= Website::getWebsiteName() ?>";
</script>

</body>
</html>
10 changes: 5 additions & 5 deletions Admin/Tailwind/tailwindInput.css
Original file line number Diff line number Diff line change
Expand Up @@ -880,23 +880,23 @@ kbd {
}

.modal-container {
@apply hidden overflow-y-auto overflow-x-hidden fixed top-[8%] right-0 left-0 z-[600000] justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-[80vh];
@apply hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-[600000] justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] ;
}

.modal-sm {
@apply overflow-hidden relative w-full max-w-md max-h-full bg-light-primary rounded-lg shadow top-[8%] dark:bg-dark-third;
@apply overflow-hidden relative w-full max-w-md max-h-full bg-light-primary rounded-lg shadow dark:bg-dark-third;
}

.modal {
@apply relative w-full max-w-2xl max-h-full bg-light-primary rounded-lg shadow top-[8%] dark:bg-dark-third;
@apply relative w-full max-w-2xl max-h-full bg-light-primary rounded-lg shadow dark:bg-dark-third;
}

.modal-lg {
@apply overflow-hidden relative w-full max-w-4xl max-h-full bg-light-primary rounded-lg shadow top-[8%] dark:bg-dark-third;
@apply overflow-hidden relative w-full max-w-4xl max-h-full bg-light-primary rounded-lg shadow dark:bg-dark-third;
}

.modal-xl {
@apply overflow-hidden relative w-full max-w-7xl max-h-full bg-light-primary rounded-lg shadow top-[8%] dark:bg-dark-third;
@apply overflow-hidden relative w-full max-w-7xl max-h-full bg-light-primary rounded-lg shadow dark:bg-dark-third;
}

.modal-header {
Expand Down
15 changes: 6 additions & 9 deletions App/Manager/Events/Emitter.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@

namespace CMW\Manager\Events;

use CMW\Manager\Collections\Collection;
use CMW\Manager\Collections\CollectionEntity;
use CMW\Manager\Loader\Loader;
use CMW\Utils\Log;
use JetBrains\PhpStorm\ExpectedValues;
use Closure;
use ReflectionClass;
use ReflectionMethod;
use function usort;

class Emitter
{
private static array $listenerCounter = array();
private static array $listenerCounter = [];
private static AbstractEvent $actualEvent;

private static function loadAttributeByEvent(array $attributeList, #[ExpectedValues(AbstractEvent::class)] string $eventName, array &$eventAttributes): void
Expand All @@ -27,7 +24,7 @@ private static function loadAttributeByEvent(array $attributeList, #[ExpectedVal
$attributeInstance = $attr->newInstance();

// todo use GlobalObject getInstance
if ($eventName !== $attributeInstance->getEventName()) {
if ($eventName !== $attributeInstance->getEventName() && $attributeInstance->getEventName() !== '*') {
continue;
}

Expand Down Expand Up @@ -77,7 +74,7 @@ private static function getCounterByMethod(#[ExpectedValues(AbstractEvent::class
private static function invokeEventMethod(#[ExpectedValues(AbstractEvent::class)] string $eventName, ReflectionMethod $method, mixed $data): void
{
$controller = $method->getDeclaringClass()->getMethod('getInstance')->invoke(null);
$method->invoke($controller, $data);
$method->invoke($controller, $data, self::$actualEvent->getName());

self::increment($eventName, $method);
}
Expand Down Expand Up @@ -113,14 +110,14 @@ private static function invoke(#[ExpectedValues(AbstractEvent::class)] string $e
public static function send(#[ExpectedValues(AbstractEvent::class)] string $eventName, mixed $data): void
{
$attributeList = Loader::getAttributeList()[Listener::class];
$eventAttributes = array();
$eventAttributes = [];

if (empty($attributeList)) {
return;
}

if (!isset(self::$listenerCounter[$eventName])) {
self::$listenerCounter[$eventName] = array();
self::$listenerCounter[$eventName] = [];
}

self::loadAttributeByEvent($attributeList, $eventName, $eventAttributes);
Expand Down
173 changes: 86 additions & 87 deletions App/Manager/Metrics/VisitsMetricsManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,50 @@

use CMW\Manager\Database\DatabaseManager;
use CMW\Manager\Env\EnvManager;
use CMW\Manager\Lang\LangManager;
use CMW\Manager\Manager\AbstractManager;
use CMW\Manager\Permission\PermissionManager;
use CMW\Manager\Router\Route;
use CMW\Utils\Client;
use CMW\Utils\File;
use CMW\Utils\Website;
use JetBrains\PhpStorm\ExpectedValues;

class VisitsMetricsManager extends AbstractManager
use PDO;
use function count;
use function date;
use function explode;
use function file;
use function fopen;
use function http_response_code;
use function mb_substr;
use function str_contains;
use function str_starts_with;
use function stream_resolve_include_path;
use function strtotime;
use const FILE_APPEND;
use const FILE_SKIP_EMPTY_LINES;
use const LOCK_EX;
use const PHP_EOL;

class VisitsMetricsManager
{
private int $maxLines = 50; // Variable data ?
private string $filePath;
private string $dirStorage;
private static ?VisitsMetricsManager $instance = null;
private ?array $cachedVisits = null;

public function __construct()
{
$this->dirStorage = EnvManager::getInstance()->getValue('DIR') . 'App/Storage/Visits';
$this->filePath = "$this->dirStorage/history.log";
}

public static function getInstance(): self
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}

public function registerVisit(Route $route): void
{
$package = explode('.', $route->getName())[0] ?? null;
Expand Down Expand Up @@ -123,54 +146,36 @@ private function getLogData(): array|false

public function getVisitsNumber(#[ExpectedValues(['all', 'monthly', 'week', 'day', 'hour'])] $period): ?int
{
$rangeStart = null;
$rangeFinish = null;

if ($period === 'monthly' || $period === 'week' || $period === 'day' || $period === 'hour'):
switch ($period):
case 'monthly':
$rangeStart = date('Y-m-d 00:00:00', strtotime('first day of this month'));
$rangeFinish = date('Y-m-d 00:00:00', strtotime('last day of this month'));
break;
case 'week':
$rangeStart = date('Y-m-d 00:00:00', strtotime('monday this week'));
$rangeFinish = date('Y-m-d 00:00:00', strtotime('sunday this week'));
break;
case 'day':
$rangeStart = date('Y-m-d 00:00:00');
$rangeFinish = date('Y-m-d 23:59:59');
break;
case 'hour':
$rangeStart = date('Y-m-d h:00:00');
$rangeFinish = date('Y-m-d h:00:00', strtotime('+1 hour'));
break;
endswitch;

$var = [
'range_start' => $rangeStart,
'range_finish' => $rangeFinish,
if ($this->cachedVisits === null) {
$db = DatabaseManager::getInstance();

$queries = [
'all' => "SELECT COUNT(DISTINCT visits_ip) AS result FROM cmw_visits",
'day' => "SELECT COUNT(DISTINCT visits_ip) AS result FROM cmw_visits WHERE visits_date >= CURDATE()",
'monthly' => "SELECT COUNT(DISTINCT visits_ip) AS result FROM cmw_visits WHERE visits_date >= DATE_FORMAT(NOW(), '%Y-%m-01')",
];

$sql = 'SELECT COUNT(DISTINCT visits_ip) AS `result` FROM cmw_visits WHERE visits_date BETWEEN (:range_start) AND (:range_finish)';
foreach ($queries as $key => $sql) {
$req = $db->prepare($sql);

$db = DatabaseManager::getInstance();
$req = $db->prepare($sql);
$res = $req->execute($var);
else:
$sql = 'SELECT COUNT(DISTINCT visits_ip) AS `result` FROM cmw_visits';
if (!$req->execute()) {
return 0;
}

$db = DatabaseManager::getInstance();
$req = $db->prepare($sql);
$res = $req->execute();
endif;
$res = $req->fetch();

if (!$res) {
return 0;
}

if ($res) {
return $req->fetch()['result'] + $this->getFileLineNumber();
$this->cachedVisits[$key] = $res['result'] ?? 0;
}
}

return $this->getFileLineNumber();
return ($this->cachedVisits[$period] ?? 0) + $this->getFileLineNumber();
}


/**
* @param string $rangeStart
* @param string $rangeFinish
Expand Down Expand Up @@ -222,78 +227,72 @@ public function getMonthlyBestVisits(): int
*/
public function getPastMonthsVisits(int $pastMonths): array
{
$currentMonth = idate('m');
$sql = "SELECT DATE_FORMAT(visits_date, '%Y-%m') AS month, COUNT(*) AS visits
FROM cmw_visits
WHERE visits_date >= STR_TO_DATE(:date_limit, '%Y-%m-%d')
GROUP BY month
ORDER BY month;";

$toReturn = [];

for ($i = 0; $i < $pastMonths; $i++) {
$targetMonth = idate('m', strtotime("-$i months"));
$targetMonthTranslate = LangManager::translate("core.months.$targetMonth");

$rangeStart = date('Y-m-d 00:00:00', strtotime("first day of -$i months"));
$rangeFinish = date('Y-m-d 23:59:59', strtotime("last day of -$i months"));
$db = DatabaseManager::getInstance();
$req = $db->prepare($sql);

$toReturn[$targetMonthTranslate] = $this->getDataVisits($rangeStart, $rangeFinish);
$dateLimit = date('Y-m-d', strtotime("-$pastMonths months")); // Pré-calcul de la date limite

if ($targetMonth === $currentMonth) {
$toReturn[$targetMonthTranslate] += $this->getFileLineNumber();
}
if (!$req->execute(['date_limit' => $dateLimit])) {
return [];
}
return array_reverse($toReturn);

return $req->fetchAll(PDO::FETCH_KEY_PAIR) ?: [];
}


/**
* @param int $pastDays
* @return array
*/
public function getPastDaysVisits(int $pastDays): array
{
$currentDay = idate('d');
$sql = "SELECT DATE(visits_date) AS day, COUNT(*) AS visits
FROM cmw_visits
WHERE visits_date >= STR_TO_DATE(:date_limit, '%Y-%m-%d')
GROUP BY day
ORDER BY day;";

$toReturn = [];

for ($i = 0; $i < $pastDays; $i++) {
$targetDay = date('d', strtotime("-$i days"));
$db = DatabaseManager::getInstance();
$req = $db->prepare($sql);

if ($targetDay === $currentDay) {
$rangeStart = date('Y-m-d 00:00:00', strtotime("-$i days"));
$rangeFinish = date('Y-m-d 23:59:59', strtotime("-$i days"));
$dateLimit = date('Y-m-d', strtotime("-$pastDays days"));

$dataVisits = $this->getDataVisits($rangeStart, $rangeFinish);
$toReturn[] = $dataVisits + $this->getFileLineNumber();
} else {
$rangeStart = date('Y-m-d 00:00:00', strtotime("-$i days"));
$rangeFinish = date('Y-m-d 23:59:59', strtotime("-$i days"));
$toReturn[] = $this->getDataVisits($rangeStart, $rangeFinish);
}
if (!$req->execute(['date_limit' => $dateLimit])) {
return [];
}

return array_reverse($toReturn);
return $req->fetchAll(PDO::FETCH_KEY_PAIR) ?: [];
}


/**
* @param int $pastWeeks
* @return array
*/
public function getPastWeeksVisits(int $pastWeeks): array
{
$currentWeeks = idate('W');

$toReturn = [];
$sql = "SELECT WEEK(visits_date, 1) AS week, COUNT(*) AS visits
FROM cmw_visits
WHERE visits_date >= STR_TO_DATE(:date_limit, '%Y-%m-%d')
GROUP BY week
ORDER BY week;";

for ($i = 0; $i < $pastWeeks; $i++) {
$targetWeek = idate('W', strtotime("-$i weeks"));

$rangeStart = date('Y-m-d 00:00:00', strtotime("-$i monday this week"));
$rangeFinish = date('Y-m-d 23:59:59', strtotime("-$i sunday this week"));
$db = DatabaseManager::getInstance();
$req = $db->prepare($sql);

$toReturn[] = $this->getDataVisits($rangeStart, $rangeFinish);
$dateLimit = date('Y-m-d', strtotime("-$pastWeeks weeks"));

if ($targetWeek === $currentWeeks) {
$toReturn[] = $this->getDataVisits($rangeStart, $rangeFinish) + $this->getFileLineNumber();
}
if (!$req->execute(['date_limit' => $dateLimit])) {
return [];
}
return array_reverse($toReturn);

return $req->fetchAll(PDO::FETCH_KEY_PAIR) ?: [];
}

/**
Expand Down
Loading