Compare commits
No commits in common. "master" and "20240720" have entirely different histories.
56 changed files with 669 additions and 1394 deletions
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"require": {
|
||||
"flashwave/index": "^0.2408.40014",
|
||||
"flashwave/sasae": "^1.1",
|
||||
"flashwave/syokuhou": "^1.2",
|
||||
"flashwave/index": "dev-master",
|
||||
"flashwave/sasae": "dev-master",
|
||||
"erusev/parsedown": "~1.6",
|
||||
"chillerlan/php-qrcode": "^4.3",
|
||||
"symfony/mailer": "^6.0",
|
||||
"matomo/device-detector": "^6.1",
|
||||
"sentry/sdk": "^4.0",
|
||||
"nesbot/carbon": "^3.7",
|
||||
"flashwave/aiwass": "^1.0"
|
||||
"flashwave/syokuhou": "dev-master"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
|
@ -34,6 +34,6 @@
|
|||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.11"
|
||||
"phpstan/phpstan": "^1.10"
|
||||
}
|
||||
}
|
||||
|
|
786
composer.lock
generated
786
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,13 +0,0 @@
|
|||
<?php
|
||||
use Index\Data\IDbConnection;
|
||||
use Index\Data\Migration\IDbMigration;
|
||||
|
||||
final class AddRoleIdString_20240916_205613 implements IDbMigration {
|
||||
public function migrate(IDbConnection $conn): void {
|
||||
$conn->execute(<<<SQL
|
||||
ALTER TABLE msz_roles
|
||||
ADD COLUMN role_string VARCHAR(20) NULL DEFAULT NULL COLLATE 'ascii_general_ci' AFTER role_id,
|
||||
ADD UNIQUE INDEX roles_string_unique (role_string);
|
||||
SQL);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu;
|
||||
|
||||
use Index\Environment;
|
||||
use Index\Data\DbTools;
|
||||
use Syokuhou\DbConfig;
|
||||
use Syokuhou\FileConfig;
|
||||
|
@ -18,9 +19,9 @@ define('MSZ_ASSETS', MSZ_ROOT . '/assets');
|
|||
|
||||
require_once MSZ_ROOT . '/vendor/autoload.php';
|
||||
|
||||
error_reporting(MSZ_DEBUG ? -1 : 0);
|
||||
Environment::setDebug(MSZ_DEBUG);
|
||||
mb_internal_encoding('UTF-8');
|
||||
date_default_timezone_set('GMT');
|
||||
date_default_timezone_set('UTC');
|
||||
|
||||
$cfg = FileConfig::fromFile(MSZ_CONFIG . '/config.cfg');
|
||||
|
||||
|
|
328
package-lock.json
generated
328
package-lock.json
generated
|
@ -80,14 +80,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@swc/core": {
|
||||
"version": "1.7.26",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.26.tgz",
|
||||
"integrity": "sha512-f5uYFf+TmMQyYIoxkn/evWhNGuUzC730dFwAKGwBVHHVoPyak1/GvJUm6i1SKl+2Hrj9oN0i3WSoWWZ4pgI8lw==",
|
||||
"version": "1.6.13",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.6.13.tgz",
|
||||
"integrity": "sha512-eailUYex6fkfaQTev4Oa3mwn0/e3mQU4H8y1WPuImYQESOQDtVrowwUGDSc19evpBbHpKtwM+hw8nLlhIsF+Tw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@swc/counter": "^0.1.3",
|
||||
"@swc/types": "^0.1.12"
|
||||
"@swc/types": "^0.1.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
|
@ -97,16 +97,16 @@
|
|||
"url": "https://opencollective.com/swc"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@swc/core-darwin-arm64": "1.7.26",
|
||||
"@swc/core-darwin-x64": "1.7.26",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.7.26",
|
||||
"@swc/core-linux-arm64-gnu": "1.7.26",
|
||||
"@swc/core-linux-arm64-musl": "1.7.26",
|
||||
"@swc/core-linux-x64-gnu": "1.7.26",
|
||||
"@swc/core-linux-x64-musl": "1.7.26",
|
||||
"@swc/core-win32-arm64-msvc": "1.7.26",
|
||||
"@swc/core-win32-ia32-msvc": "1.7.26",
|
||||
"@swc/core-win32-x64-msvc": "1.7.26"
|
||||
"@swc/core-darwin-arm64": "1.6.13",
|
||||
"@swc/core-darwin-x64": "1.6.13",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.6.13",
|
||||
"@swc/core-linux-arm64-gnu": "1.6.13",
|
||||
"@swc/core-linux-arm64-musl": "1.6.13",
|
||||
"@swc/core-linux-x64-gnu": "1.6.13",
|
||||
"@swc/core-linux-x64-musl": "1.6.13",
|
||||
"@swc/core-win32-arm64-msvc": "1.6.13",
|
||||
"@swc/core-win32-ia32-msvc": "1.6.13",
|
||||
"@swc/core-win32-x64-msvc": "1.6.13"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/helpers": "*"
|
||||
|
@ -118,9 +118,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@swc/core-darwin-arm64": {
|
||||
"version": "1.7.26",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.26.tgz",
|
||||
"integrity": "sha512-FF3CRYTg6a7ZVW4yT9mesxoVVZTrcSWtmZhxKCYJX9brH4CS/7PRPjAKNk6kzWgWuRoglP7hkjQcd6EpMcZEAw==",
|
||||
"version": "1.6.13",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.6.13.tgz",
|
||||
"integrity": "sha512-SOF4buAis72K22BGJ3N8y88mLNfxLNprTuJUpzikyMGrvkuBFNcxYtMhmomO0XHsgLDzOJ+hWzcgjRNzjMsUcQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -134,9 +134,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@swc/core-darwin-x64": {
|
||||
"version": "1.7.26",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.7.26.tgz",
|
||||
"integrity": "sha512-az3cibZdsay2HNKmc4bjf62QVukuiMRh5sfM5kHR/JMTrLyS6vSw7Ihs3UTkZjUxkLTT8ro54LI6sV6sUQUbLQ==",
|
||||
"version": "1.6.13",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.6.13.tgz",
|
||||
"integrity": "sha512-AW8akFSC+tmPE6YQQvK9S2A1B8pjnXEINg+gGgw0KRUUXunvu1/OEOeC5L2Co1wAwhD7bhnaefi06Qi9AiwOag==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -150,9 +150,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm-gnueabihf": {
|
||||
"version": "1.7.26",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.26.tgz",
|
||||
"integrity": "sha512-VYPFVJDO5zT5U3RpCdHE5v1gz4mmR8BfHecUZTmD2v1JeFY6fv9KArJUpjrHEEsjK/ucXkQFmJ0jaiWXmpOV9Q==",
|
||||
"version": "1.6.13",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.6.13.tgz",
|
||||
"integrity": "sha512-f4gxxvDXVUm2HLYXRd311mSrmbpQF2MZ4Ja6XCQz1hWAxXdhRl1gpnZ+LH/xIfGSwQChrtLLVrkxdYUCVuIjFg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
@ -166,9 +166,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm64-gnu": {
|
||||
"version": "1.7.26",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.26.tgz",
|
||||
"integrity": "sha512-YKevOV7abpjcAzXrhsl+W48Z9mZvgoVs2eP5nY+uoMAdP2b3GxC0Df1Co0I90o2lkzO4jYBpTMcZlmUXLdXn+Q==",
|
||||
"version": "1.6.13",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.6.13.tgz",
|
||||
"integrity": "sha512-Nf/eoW2CbG8s+9JoLtjl9FByBXyQ5cjdBsA4efO7Zw4p+YSuXDgc8HRPC+E2+ns0praDpKNZtLvDtmF2lL+2Gg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -182,9 +182,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm64-musl": {
|
||||
"version": "1.7.26",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.26.tgz",
|
||||
"integrity": "sha512-3w8iZICMkQQON0uIcvz7+Q1MPOW6hJ4O5ETjA0LSP/tuKqx30hIniCGOgPDnv3UTMruLUnQbtBwVCZTBKR3Rkg==",
|
||||
"version": "1.6.13",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.6.13.tgz",
|
||||
"integrity": "sha512-2OysYSYtdw79prJYuKIiux/Gj0iaGEbpS2QZWCIY4X9sGoETJ5iMg+lY+YCrIxdkkNYd7OhIbXdYFyGs/w5LDg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -198,9 +198,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-x64-gnu": {
|
||||
"version": "1.7.26",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.26.tgz",
|
||||
"integrity": "sha512-c+pp9Zkk2lqb06bNGkR2Looxrs7FtGDMA4/aHjZcCqATgp348hOKH5WPvNLBl+yPrISuWjbKDVn3NgAvfvpH4w==",
|
||||
"version": "1.6.13",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.6.13.tgz",
|
||||
"integrity": "sha512-PkR4CZYJNk5hcd2+tMWBpnisnmYsUzazI1O5X7VkIGFcGePTqJ/bWlfUIVVExWxvAI33PQFzLbzmN5scyIUyGQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -214,9 +214,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-x64-musl": {
|
||||
"version": "1.7.26",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.26.tgz",
|
||||
"integrity": "sha512-PgtyfHBF6xG87dUSSdTJHwZ3/8vWZfNIXQV2GlwEpslrOkGqy+WaiiyE7Of7z9AvDILfBBBcJvJ/r8u980wAfQ==",
|
||||
"version": "1.6.13",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.6.13.tgz",
|
||||
"integrity": "sha512-OdsY7wryTxCKwGQcwW9jwWg3cxaHBkTTHi91+5nm7hFPpmZMz1HivJrWAMwVE7iXFw+M4l6ugB/wCvpYrUAAjA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -230,9 +230,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-arm64-msvc": {
|
||||
"version": "1.7.26",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.26.tgz",
|
||||
"integrity": "sha512-9TNXPIJqFynlAOrRD6tUQjMq7KApSklK3R/tXgIxc7Qx+lWu8hlDQ/kVPLpU7PWvMMwC/3hKBW+p5f+Tms1hmA==",
|
||||
"version": "1.6.13",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.6.13.tgz",
|
||||
"integrity": "sha512-ap6uNmYjwk9M/+bFEuWRNl3hq4VqgQ/Lk+ID/F5WGqczNr0L7vEf+pOsRAn0F6EV+o/nyb3ePt8rLhE/wjHpPg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
@ -246,9 +246,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-ia32-msvc": {
|
||||
"version": "1.7.26",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.26.tgz",
|
||||
"integrity": "sha512-9YngxNcG3177GYdsTum4V98Re+TlCeJEP4kEwEg9EagT5s3YejYdKwVAkAsJszzkXuyRDdnHUpYbTrPG6FiXrQ==",
|
||||
"version": "1.6.13",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.6.13.tgz",
|
||||
"integrity": "sha512-IJ8KH4yIUHTnS/U1jwQmtbfQals7zWPG0a9hbEfIr4zI0yKzjd83lmtS09lm2Q24QBWOCFGEEbuZxR4tIlvfzA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
|
@ -262,9 +262,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-x64-msvc": {
|
||||
"version": "1.7.26",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.26.tgz",
|
||||
"integrity": "sha512-VR+hzg9XqucgLjXxA13MtV5O3C0bK0ywtLIBw/+a+O+Oc6mxFWHtdUeXDbIi5AiPbn0fjgVJMqYnyjGyyX8u0w==",
|
||||
"version": "1.6.13",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.6.13.tgz",
|
||||
"integrity": "sha512-f6/sx6LMuEnbuxtiSL/EkR0Y6qUHFw1XVrh6rwzKXptTipUdOY+nXpKoh+1UsBm/r7H0/5DtOdrn3q5ZHbFZjQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
@ -284,9 +284,9 @@
|
|||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@swc/types": {
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.12.tgz",
|
||||
"integrity": "sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==",
|
||||
"version": "0.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.9.tgz",
|
||||
"integrity": "sha512-qKnCno++jzcJ4lM4NTfYifm1EFSCeIfKiAHAfkENZAV5Kl9PjJIyd2yeeVv6c/2CckuLyv2NmRC5pv6pm2WQBg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@swc/counter": "^0.1.3"
|
||||
|
@ -314,9 +314,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.4.20",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
|
||||
"integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==",
|
||||
"version": "10.4.19",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz",
|
||||
"integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
@ -333,11 +333,11 @@
|
|||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.23.3",
|
||||
"caniuse-lite": "^1.0.30001646",
|
||||
"browserslist": "^4.23.0",
|
||||
"caniuse-lite": "^1.0.30001599",
|
||||
"fraction.js": "^4.3.7",
|
||||
"normalize-range": "^0.1.2",
|
||||
"picocolors": "^1.0.1",
|
||||
"picocolors": "^1.0.0",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
"bin": {
|
||||
|
@ -357,9 +357,9 @@
|
|||
"license": "ISC"
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.23.3",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz",
|
||||
"integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==",
|
||||
"version": "4.23.2",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz",
|
||||
"integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
@ -376,9 +376,9 @@
|
|||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001646",
|
||||
"electron-to-chromium": "^1.5.4",
|
||||
"node-releases": "^2.0.18",
|
||||
"caniuse-lite": "^1.0.30001640",
|
||||
"electron-to-chromium": "^1.4.820",
|
||||
"node-releases": "^2.0.14",
|
||||
"update-browserslist-db": "^1.1.0"
|
||||
},
|
||||
"bin": {
|
||||
|
@ -417,9 +417,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001660",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz",
|
||||
"integrity": "sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==",
|
||||
"version": "1.0.30001642",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz",
|
||||
"integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
@ -529,12 +529,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/cssnano": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.0.6.tgz",
|
||||
"integrity": "sha512-54woqx8SCbp8HwvNZYn68ZFAepuouZW4lTwiMVnBErM3VkO7/Sd4oTOt3Zz3bPx3kxQ36aISppyXj2Md4lg8bw==",
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.0.4.tgz",
|
||||
"integrity": "sha512-rQgpZra72iFjiheNreXn77q1haS2GEy69zCMbu4cpXCFPMQF+D4Ik5V7ktMzUF/sA7xCIgcqHwGPnCD+0a1vHg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cssnano-preset-default": "^7.0.6",
|
||||
"cssnano-preset-default": "^7.0.4",
|
||||
"lilconfig": "^3.1.2"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -549,41 +549,41 @@
|
|||
}
|
||||
},
|
||||
"node_modules/cssnano-preset-default": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.6.tgz",
|
||||
"integrity": "sha512-ZzrgYupYxEvdGGuqL+JKOY70s7+saoNlHSCK/OGn1vB2pQK8KSET8jvenzItcY+kA7NoWvfbb/YhlzuzNKjOhQ==",
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.4.tgz",
|
||||
"integrity": "sha512-jQ6zY9GAomQX7/YNLibMEsRZguqMUGuupXcEk2zZ+p3GUxwCAsobqPYE62VrJ9qZ0l9ltrv2rgjwZPBIFIjYtw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.23.3",
|
||||
"browserslist": "^4.23.1",
|
||||
"css-declaration-sorter": "^7.2.0",
|
||||
"cssnano-utils": "^5.0.0",
|
||||
"postcss-calc": "^10.0.2",
|
||||
"postcss-colormin": "^7.0.2",
|
||||
"postcss-convert-values": "^7.0.4",
|
||||
"postcss-discard-comments": "^7.0.3",
|
||||
"postcss-discard-duplicates": "^7.0.1",
|
||||
"postcss-calc": "^10.0.0",
|
||||
"postcss-colormin": "^7.0.1",
|
||||
"postcss-convert-values": "^7.0.2",
|
||||
"postcss-discard-comments": "^7.0.1",
|
||||
"postcss-discard-duplicates": "^7.0.0",
|
||||
"postcss-discard-empty": "^7.0.0",
|
||||
"postcss-discard-overridden": "^7.0.0",
|
||||
"postcss-merge-longhand": "^7.0.4",
|
||||
"postcss-merge-rules": "^7.0.4",
|
||||
"postcss-merge-longhand": "^7.0.2",
|
||||
"postcss-merge-rules": "^7.0.2",
|
||||
"postcss-minify-font-values": "^7.0.0",
|
||||
"postcss-minify-gradients": "^7.0.0",
|
||||
"postcss-minify-params": "^7.0.2",
|
||||
"postcss-minify-selectors": "^7.0.4",
|
||||
"postcss-minify-params": "^7.0.1",
|
||||
"postcss-minify-selectors": "^7.0.2",
|
||||
"postcss-normalize-charset": "^7.0.0",
|
||||
"postcss-normalize-display-values": "^7.0.0",
|
||||
"postcss-normalize-positions": "^7.0.0",
|
||||
"postcss-normalize-repeat-style": "^7.0.0",
|
||||
"postcss-normalize-string": "^7.0.0",
|
||||
"postcss-normalize-timing-functions": "^7.0.0",
|
||||
"postcss-normalize-unicode": "^7.0.2",
|
||||
"postcss-normalize-unicode": "^7.0.1",
|
||||
"postcss-normalize-url": "^7.0.0",
|
||||
"postcss-normalize-whitespace": "^7.0.0",
|
||||
"postcss-ordered-values": "^7.0.1",
|
||||
"postcss-reduce-initial": "^7.0.2",
|
||||
"postcss-reduce-initial": "^7.0.1",
|
||||
"postcss-reduce-transforms": "^7.0.0",
|
||||
"postcss-svgo": "^7.0.1",
|
||||
"postcss-unique-selectors": "^7.0.3"
|
||||
"postcss-unique-selectors": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.12.0 || ^20.9.0 || >=22.0"
|
||||
|
@ -703,9 +703,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.23",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.23.tgz",
|
||||
"integrity": "sha512-mBhODedOXg4v5QWwl21DjM5amzjmI1zw9EPrPK/5Wx7C8jt33bpZNrC7OhHUG3pxRtbLpr3W2dXT+Ph1SsfRZA==",
|
||||
"version": "1.4.829",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.829.tgz",
|
||||
"integrity": "sha512-5qp1N2POAfW0u1qGAxXEtz6P7bO1m6gpZr5hdf5ve6lxpLM7MpiM4jIPz7xcrNlClQMafbyUDDWjlIQZ1Mw0Rw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/entities": {
|
||||
|
@ -721,9 +721,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
|
||||
"integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
|
@ -831,9 +831,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.18",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
|
||||
"integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
|
||||
"version": "2.0.17",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.17.tgz",
|
||||
"integrity": "sha512-Ww6ZlOiEQfPfXM45v17oabk77Z7mg5bOt7AjDyzy7RjK9OrLrLC8dyZQoAPEOtFX9SaNf1Tdvr5gRJWdTJj7GA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/normalize-range": {
|
||||
|
@ -878,15 +878,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
|
||||
"integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
|
||||
"integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.47",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
|
||||
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
|
||||
"version": "8.4.39",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz",
|
||||
"integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
@ -904,20 +904,20 @@
|
|||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.7",
|
||||
"picocolors": "^1.1.0",
|
||||
"source-map-js": "^1.2.1"
|
||||
"picocolors": "^1.0.1",
|
||||
"source-map-js": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-calc": {
|
||||
"version": "10.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.0.2.tgz",
|
||||
"integrity": "sha512-DT/Wwm6fCKgpYVI7ZEWuPJ4az8hiEHtCUeYjZXqU7Ou4QqYh1Df2yCQ7Ca6N7xqKPFkxN3fhf+u9KSoOCJNAjg==",
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.0.0.tgz",
|
||||
"integrity": "sha512-OmjhudoNTP0QleZCwl1i6NeBwN+5MZbY5ersLZz69mjJiDVv/p57RjRuKDkHeDWr4T+S97wQfsqRTNoDHB2e3g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"postcss-selector-parser": "^6.1.2",
|
||||
"postcss-selector-parser": "^6.0.16",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -928,12 +928,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss-colormin": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.2.tgz",
|
||||
"integrity": "sha512-YntRXNngcvEvDbEjTdRWGU606eZvB5prmHG4BF0yLmVpamXbpsRJzevyy6MZVyuecgzI2AWAlvFi8DAeCqwpvA==",
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.1.tgz",
|
||||
"integrity": "sha512-uszdT0dULt3FQs47G5UHCduYK+FnkLYlpu1HpWu061eGsKZ7setoG7kA+WC9NQLsOJf69D5TxGHgnAdRgylnFQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.23.3",
|
||||
"browserslist": "^4.23.1",
|
||||
"caniuse-api": "^3.0.0",
|
||||
"colord": "^2.9.3",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
|
@ -946,12 +946,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss-convert-values": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-7.0.4.tgz",
|
||||
"integrity": "sha512-e2LSXPqEHVW6aoGbjV9RsSSNDO3A0rZLCBxN24zvxF25WknMPpX8Dm9UxxThyEbaytzggRuZxaGXqaOhxQ514Q==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-7.0.2.tgz",
|
||||
"integrity": "sha512-MuZIF6HJ4izko07Q0TgW6pClalI4al6wHRNPkFzqQdwAwG7hPn0lA58VZdxyb2Vl5AYjJ1piO+jgF9EnTjQwQQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.23.3",
|
||||
"browserslist": "^4.23.1",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -962,12 +962,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss-discard-comments": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-7.0.3.tgz",
|
||||
"integrity": "sha512-q6fjd4WU4afNhWOA2WltHgCbkRhZPgQe7cXF74fuVB/ge4QbM9HEaOIzGSiMvM+g/cOsNAUGdf2JDzqA2F8iLA==",
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-7.0.1.tgz",
|
||||
"integrity": "sha512-GVrQxUOhmle1W6jX2SvNLt4kmN+JYhV7mzI6BMnkAWR9DtVvg8e67rrV0NfdWhn7x1zxvzdWkMBPdBDCls+uwQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"postcss-selector-parser": "^6.1.2"
|
||||
"postcss-selector-parser": "^6.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.12.0 || ^20.9.0 || >=22.0"
|
||||
|
@ -977,9 +977,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss-discard-duplicates": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.1.tgz",
|
||||
"integrity": "sha512-oZA+v8Jkpu1ct/xbbrntHRsfLGuzoP+cpt0nJe5ED2FQF8n8bJtn7Bo28jSmBYwqgqnqkuSXJfSUEE7if4nClQ==",
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.0.tgz",
|
||||
"integrity": "sha512-bAnSuBop5LpAIUmmOSsuvtKAAKREB6BBIYStWUTGq8oG5q9fClDMMuY8i4UPI/cEcDx2TN+7PMnXYIId20UVDw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.12.0 || ^20.9.0 || >=22.0"
|
||||
|
@ -1013,13 +1013,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss-merge-longhand": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-7.0.4.tgz",
|
||||
"integrity": "sha512-zer1KoZA54Q8RVHKOY5vMke0cCdNxMP3KBfDerjH/BYHh4nCIh+1Yy0t1pAEQF18ac/4z3OFclO+ZVH8azjR4A==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-7.0.2.tgz",
|
||||
"integrity": "sha512-06vrW6ZWi9qeP7KMS9fsa9QW56+tIMW55KYqF7X3Ccn+NI2pIgPV6gFfvXTMQ05H90Y5DvnCDPZ2IuHa30PMUg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"postcss-value-parser": "^4.2.0",
|
||||
"stylehacks": "^7.0.4"
|
||||
"stylehacks": "^7.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.12.0 || ^20.9.0 || >=22.0"
|
||||
|
@ -1029,15 +1029,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss-merge-rules": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-7.0.4.tgz",
|
||||
"integrity": "sha512-ZsaamiMVu7uBYsIdGtKJ64PkcQt6Pcpep/uO90EpLS3dxJi6OXamIobTYcImyXGoW0Wpugh7DSD3XzxZS9JCPg==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-7.0.2.tgz",
|
||||
"integrity": "sha512-VAR47UNvRsdrTHLe7TV1CeEtF9SJYR5ukIB9U4GZyZOptgtsS20xSxy+k5wMrI3udST6O1XuIn7cjQkg7sDAAw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.23.3",
|
||||
"browserslist": "^4.23.1",
|
||||
"caniuse-api": "^3.0.0",
|
||||
"cssnano-utils": "^5.0.0",
|
||||
"postcss-selector-parser": "^6.1.2"
|
||||
"postcss-selector-parser": "^6.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.12.0 || ^20.9.0 || >=22.0"
|
||||
|
@ -1079,12 +1079,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss-minify-params": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-7.0.2.tgz",
|
||||
"integrity": "sha512-nyqVLu4MFl9df32zTsdcLqCFfE/z2+f8GE1KHPxWOAmegSo6lpV2GNy5XQvrzwbLmiU7d+fYay4cwto1oNdAaQ==",
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-7.0.1.tgz",
|
||||
"integrity": "sha512-e+Xt8xErSRPgSRFxHeBCSxMiO8B8xng7lh8E0A5ep1VfwYhY8FXhu4Q3APMjgx9YDDbSp53IBGENrzygbUvgUQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.23.3",
|
||||
"browserslist": "^4.23.1",
|
||||
"cssnano-utils": "^5.0.0",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
|
@ -1096,13 +1096,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss-minify-selectors": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.0.4.tgz",
|
||||
"integrity": "sha512-JG55VADcNb4xFCf75hXkzc1rNeURhlo7ugf6JjiiKRfMsKlDzN9CXHZDyiG6x/zGchpjQS+UAgb1d4nqXqOpmA==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.0.2.tgz",
|
||||
"integrity": "sha512-dCzm04wqW1uqLmDZ41XYNBJfjgps3ZugDpogAmJXoCb5oCiTzIX4oPXXKxDpTvWOnKxQKR4EbV4ZawJBLcdXXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"postcss-selector-parser": "^6.1.2"
|
||||
"postcss-selector-parser": "^6.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.12.0 || ^20.9.0 || >=22.0"
|
||||
|
@ -1199,12 +1199,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss-normalize-unicode": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.2.tgz",
|
||||
"integrity": "sha512-ztisabK5C/+ZWBdYC+Y9JCkp3M9qBv/XFvDtSw0d/XwfT3UaKeW/YTm/MD/QrPNxuecia46vkfEhewjwcYFjkg==",
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.1.tgz",
|
||||
"integrity": "sha512-PTPGdY9xAkTw+8ZZ71DUePb7M/Vtgkbbq+EoI33EuyQEzbKemEQMhe5QSr0VP5UfZlreANDPxSfcdSprENcbsg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.23.3",
|
||||
"browserslist": "^4.23.1",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -1261,12 +1261,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss-reduce-initial": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.2.tgz",
|
||||
"integrity": "sha512-pOnu9zqQww7dEKf62Nuju6JgsW2V0KRNBHxeKohU+JkHd/GAH5uvoObqFLqkeB2n20mr6yrlWDvo5UBU5GnkfA==",
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.1.tgz",
|
||||
"integrity": "sha512-0JDUSV4bGB5FGM5g8MkS+rvqKukJZ7OTHw/lcKn7xPNqeaqJyQbUO8/dJpvyTpaVwPsd3Uc33+CfNzdVowp2WA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.23.3",
|
||||
"browserslist": "^4.23.1",
|
||||
"caniuse-api": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -1292,9 +1292,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss-selector-parser": {
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
|
||||
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz",
|
||||
"integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
|
@ -1321,12 +1321,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss-unique-selectors": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-7.0.3.tgz",
|
||||
"integrity": "sha512-J+58u5Ic5T1QjP/LDV9g3Cx4CNOgB5vz+kM6+OxHHhFACdcDeKhBXjQmB7fnIZM12YSTvsL0Opwco83DmacW2g==",
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-7.0.1.tgz",
|
||||
"integrity": "sha512-MH7QE/eKUftTB5ta40xcHLl7hkZjgDFydpfTK+QWXeHxghVt3VoPqYL5/G+zYZPPIs+8GuqFXSTgxBSoB1RZtQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"postcss-selector-parser": "^6.1.2"
|
||||
"postcss-selector-parser": "^6.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.12.0 || ^20.9.0 || >=22.0"
|
||||
|
@ -1360,9 +1360,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
|
||||
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
|
@ -1379,13 +1379,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/stylehacks": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.4.tgz",
|
||||
"integrity": "sha512-i4zfNrGMt9SB4xRK9L83rlsFCgdGANfeDAYacO1pkqcE7cRHPdWHwnKZVz7WY17Veq/FvyYsRAU++Ga+qDFIww==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.2.tgz",
|
||||
"integrity": "sha512-HdkWZS9b4gbgYTdMg4gJLmm7biAUug1qTqXjS+u8X+/pUd+9Px1E+520GnOW3rST9MNsVOVpsJG+mPHNosxjOQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.23.3",
|
||||
"postcss-selector-parser": "^6.1.2"
|
||||
"browserslist": "^4.23.1",
|
||||
"postcss-selector-parser": "^6.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.12.0 || ^20.9.0 || >=22.0"
|
||||
|
@ -1429,9 +1429,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.32.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.32.0.tgz",
|
||||
"integrity": "sha512-v3Gtw3IzpBJ0ugkxEX8U0W6+TnPKRRCWGh1jC/iM/e3Ki5+qvO1L1EAZ56bZasc64aXHwRHNIQEzm6//i5cemQ==",
|
||||
"version": "5.31.3",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.31.3.tgz",
|
||||
"integrity": "sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
|
@ -1453,9 +1453,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
|
||||
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
|
||||
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
|
|
|
@ -4,6 +4,3 @@ parameters:
|
|||
- src
|
||||
bootstrapFiles:
|
||||
- misuzu.php
|
||||
dynamicConstantNames:
|
||||
- MSZ_CLI
|
||||
- MSZ_DEBUG
|
||||
|
|
|
@ -3,10 +3,9 @@ namespace Misuzu;
|
|||
|
||||
use stdClass;
|
||||
use RuntimeException;
|
||||
use Index\DateTime;
|
||||
use Misuzu\Forum\ForumTopicInfo;
|
||||
use Misuzu\Parsers\Parser;
|
||||
use Index\XDateTime;
|
||||
use Carbon\CarbonImmutable;
|
||||
|
||||
$authInfo = $msz->getAuthInfo();
|
||||
if(!$authInfo->isLoggedIn())
|
||||
|
@ -153,11 +152,11 @@ if(!empty($_POST)) {
|
|||
if($mode === 'create') {
|
||||
$postTimeout = $cfg->getInteger('forum.posting.timeout', 5);
|
||||
if($postTimeout > 0) {
|
||||
$postTimeoutThreshold = new CarbonImmutable(sprintf('-%d seconds', $postTimeout));
|
||||
$postTimeoutThreshold = DateTime::now()->modify(sprintf('-%d seconds', $postTimeout));
|
||||
$lastPostCreatedAt = $forumPosts->getUserLastPostCreatedAt($currentUser);
|
||||
|
||||
if(XDateTime::compare($lastPostCreatedAt, $postTimeoutThreshold) > 0) {
|
||||
$waitSeconds = $postTimeout + ((int)$lastPostCreatedAt->format('U') - time());
|
||||
if($lastPostCreatedAt->isMoreThan($postTimeoutThreshold)) {
|
||||
$waitSeconds = $postTimeout + ($lastPostCreatedAt->getUnixTimeSeconds() - time());
|
||||
|
||||
$notices[] = sprintf("You're posting too quickly! Please wait %s seconds before posting again.", number_format($waitSeconds));
|
||||
$notices[] = "It's possible that your post went through successfully and you pressed the submit button twice by accident.";
|
||||
|
|
|
@ -3,9 +3,9 @@ namespace Misuzu;
|
|||
|
||||
use DateTimeInterface;
|
||||
use RuntimeException;
|
||||
use Index\DateTime;
|
||||
use Index\XArray;
|
||||
use Misuzu\Changelog\Changelog;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\{XArray,XDateTime};
|
||||
|
||||
$authInfo = $msz->getAuthInfo();
|
||||
if(!$authInfo->getPerms('global')->check(Perm::G_CL_CHANGES_MANAGE))
|
||||
|
@ -58,8 +58,8 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
|||
if(empty($createdAt))
|
||||
$createdAt = null;
|
||||
else {
|
||||
$createdAt = CarbonImmutable::createFromFormat(DateTimeInterface::ATOM, $createdAt . ':00Z');
|
||||
if((int)$createdAt->format('U') < 0)
|
||||
$createdAt = DateTime::createFromFormat(DateTimeInterface::ATOM, $createdAt . ':00Z');
|
||||
if($createdAt->getUnixTimeSeconds() < 0)
|
||||
$createdAt = null;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
|||
$summary = null;
|
||||
if($body === $changeInfo->getBody())
|
||||
$body = null;
|
||||
if($createdAt !== null && XDateTime::compare($createdAt, $changeInfo->getCreatedAt()) === 0)
|
||||
if($createdAt !== null && $createdAt->equals($changeInfo->getCreatedAt()))
|
||||
$createdAt = null;
|
||||
$updateUserInfo = $userId !== $changeInfo->getUserId();
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ namespace Misuzu;
|
|||
|
||||
use DateTimeInterface;
|
||||
use RuntimeException;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
|
||||
$authInfo = $msz->getAuthInfo();
|
||||
if(!$authInfo->getPerms('user')->check(Perm::U_BANS_MANAGE))
|
||||
|
@ -56,7 +56,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
|||
if($expires === -1) {
|
||||
$expires = null;
|
||||
} elseif($expires === -2) {
|
||||
$expires = CarbonImmutable::createFromFormat(DateTimeInterface::ATOM, $expiresCustom . ':00Z');
|
||||
$expires = DateTime::createFromFormat(DateTimeInterface::ATOM, $expiresCustom . ':00Z');
|
||||
} else {
|
||||
echo 'Invalid duration specified.';
|
||||
break;
|
||||
|
|
|
@ -42,7 +42,6 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
|||
break;
|
||||
}
|
||||
|
||||
$roleString = (string)filter_input(INPUT_POST, 'ur_string');
|
||||
$roleName = (string)filter_input(INPUT_POST, 'ur_name');
|
||||
$roleHide = !empty($_POST['ur_hidden']);
|
||||
$roleLeavable = !empty($_POST['ur_leavable']);
|
||||
|
@ -55,7 +54,6 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
|||
$colourBlue = (int)filter_input(INPUT_POST, 'ur_col_blue', FILTER_SANITIZE_NUMBER_INT);
|
||||
|
||||
Template::set([
|
||||
'role_ur_string' => $roleString,
|
||||
'role_ur_name' => $roleName,
|
||||
'role_ur_hidden' => $roleHide,
|
||||
'role_ur_leavable' => $roleLeavable,
|
||||
|
@ -98,31 +96,11 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
|||
break;
|
||||
}
|
||||
|
||||
if(strlen($roleString) > 20) {
|
||||
echo 'Role string may not be longer than 20 characters.';
|
||||
break;
|
||||
}
|
||||
if(strlen($roleString) > 1 && !ctype_alpha($roleString[0])) {
|
||||
echo 'Role string most start with an alphabetical character.';
|
||||
break;
|
||||
}
|
||||
|
||||
if($isNew) {
|
||||
$roleInfo = $roles->createRole(
|
||||
$roleName,
|
||||
$roleRank,
|
||||
$roleColour,
|
||||
string: $roleString,
|
||||
title: $roleTitle,
|
||||
description: $roleDesc,
|
||||
hidden: $roleHide,
|
||||
leavable: $roleLeavable
|
||||
);
|
||||
$roleInfo = $roles->createRole($roleName, $roleRank, $roleColour, $roleTitle, $roleDesc, $roleHide, $roleLeavable);
|
||||
} else {
|
||||
if($roleName === $roleInfo->getName())
|
||||
$roleName = null;
|
||||
if($roleString === $roleInfo->getString())
|
||||
$roleString = null;
|
||||
if($roleHide === $roleInfo->isHidden())
|
||||
$roleHide = null;
|
||||
if($roleLeavable === $roleInfo->isLeavable())
|
||||
|
@ -137,17 +115,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
|||
if((string)$roleColour === (string)$roleInfo->getColour())
|
||||
$roleColour = null;
|
||||
|
||||
$roles->updateRole(
|
||||
$roleInfo,
|
||||
string: $roleString,
|
||||
name: $roleName,
|
||||
rank: $roleRank,
|
||||
colour: $roleColour,
|
||||
title: $roleTitle,
|
||||
description: $roleDesc,
|
||||
hidden: $roleHide,
|
||||
leavable: $roleLeavable
|
||||
);
|
||||
$roles->updateRole($roleInfo, $roleName, $roleRank, $roleColour, $roleTitle, $roleDesc, $roleHide, $roleLeavable);
|
||||
}
|
||||
|
||||
$msz->createAuditLog(
|
||||
|
|
|
@ -5,6 +5,7 @@ use stdClass;
|
|||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Index\ByteFormat;
|
||||
use Index\DateTime;
|
||||
use Misuzu\Parsers\Parser;
|
||||
use Misuzu\Users\User;
|
||||
use Misuzu\Users\Assets\UserAvatarAsset;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
namespace Misuzu\AuditLog;
|
||||
|
||||
use ValueError;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
use Index\Net\IPAddress;
|
||||
|
||||
|
@ -47,8 +47,8 @@ class AuditLogInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function getRemoteAddressRaw(): string {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu\Auth;
|
||||
|
||||
use Index\XArray;
|
||||
use Misuzu\Auth\SessionInfo;
|
||||
use Misuzu\Forum\ForumCategoryInfo;
|
||||
use Misuzu\Perms\IPermissionResult;
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
namespace Misuzu\Auth;
|
||||
|
||||
use RuntimeException;
|
||||
use Misuzu\Users\{UsersContext,UserInfo};
|
||||
use Aiwass\Server\{RpcActionHandler,RpcProcedure};
|
||||
use Syokuhou\IConfig;
|
||||
|
||||
final class AuthRpcActions extends RpcActionHandler {
|
||||
public function __construct(
|
||||
private IConfig $impersonateConfig,
|
||||
private UsersContext $usersCtx,
|
||||
private AuthContext $authCtx
|
||||
) {}
|
||||
|
||||
private function canImpersonateUserId(UserInfo $impersonator, string $targetId): bool {
|
||||
if($impersonator->isSuperUser())
|
||||
return true;
|
||||
|
||||
$whitelist = $this->impersonateConfig->getArray(sprintf('allow.u%s', $impersonator->getId()));
|
||||
return in_array($targetId, $whitelist, true);
|
||||
}
|
||||
|
||||
#[RpcProcedure('misuzu:auth:attemptMisuzuAuth')]
|
||||
public function procAttemptMisuzuAuth(string $remoteAddr, string $token): array {
|
||||
$tokenInfo = $this->authCtx->createAuthTokenPacker()->unpack($token);
|
||||
if(!$tokenInfo->isEmpty())
|
||||
$token = $tokenInfo->getSessionToken();
|
||||
|
||||
$sessions = $this->authCtx->getSessions();
|
||||
try {
|
||||
$sessionInfo = $sessions->getSession(sessionToken: $token);
|
||||
} catch(RuntimeException $ex) {
|
||||
return ['method' => 'misuzu', 'error' => 'token'];
|
||||
}
|
||||
|
||||
if($sessionInfo->hasExpired()) {
|
||||
$sessions->deleteSessions(sessionInfos: $sessionInfo);
|
||||
return ['method' => 'misuzu', 'error' => 'expired'];
|
||||
}
|
||||
|
||||
$sessions->recordSessionActivity(sessionInfo: $sessionInfo, remoteAddr: $remoteAddr);
|
||||
|
||||
$users = $this->usersCtx->getUsers();
|
||||
$userInfo = $users->getUser($sessionInfo->getUserId(), 'id');
|
||||
if($tokenInfo->hasImpersonatedUserId() && $this->canImpersonateUserId($userInfo, $tokenInfo->getImpersonatedUserId())) {
|
||||
$userInfoReal = $userInfo;
|
||||
|
||||
try {
|
||||
$userInfo = $users->getUser($tokenInfo->getImpersonatedUserId(), 'id');
|
||||
} catch(RuntimeException $ex) {
|
||||
$userInfo = $userInfoReal;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'method' => 'misuzu',
|
||||
'type' => 'user',
|
||||
'user' => $userInfo->getId(),
|
||||
'expires' => $sessionInfo->getExpiresTime(),
|
||||
];
|
||||
}
|
||||
}
|
|
@ -2,8 +2,8 @@
|
|||
namespace Misuzu\Auth;
|
||||
|
||||
use RuntimeException;
|
||||
use Index\UriBase64;
|
||||
use Index\IO\MemoryStream;
|
||||
use Index\Serialisation\UriBase64;
|
||||
|
||||
class AuthTokenPacker {
|
||||
private const EPOCH_V2 = 1682985600;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?php
|
||||
namespace Misuzu\Auth;
|
||||
|
||||
use Misuzu\ClientInfo;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
use Index\Net\IPAddress;
|
||||
use Misuzu\ClientInfo;
|
||||
|
||||
class LoginAttemptInfo {
|
||||
public function __construct(
|
||||
|
@ -57,8 +57,8 @@ class LoginAttemptInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function getUserAgentString(): string {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu\Auth;
|
||||
|
||||
use Index\TimeSpan;
|
||||
use Index\Data\DbStatementCache;
|
||||
use Index\Data\IDbConnection;
|
||||
use Index\Net\IPAddress;
|
||||
|
@ -22,12 +23,14 @@ class LoginAttempts {
|
|||
?bool $success = null,
|
||||
UserInfo|string|null $userInfo = null,
|
||||
IPAddress|string|null $remoteAddr = null,
|
||||
int|null $timeRange = null
|
||||
TimeSpan|int|null $timeRange = null
|
||||
): int {
|
||||
if($userInfo instanceof UserInfo)
|
||||
$userInfo = $userInfo->getId();
|
||||
if($remoteAddr instanceof IPAddress)
|
||||
$remoteAddr = (string)$remoteAddr;
|
||||
if($timeRange instanceof TimeSpan)
|
||||
$timeRange = (int)$timeRange->totalSeconds();
|
||||
|
||||
$hasSuccess = $success !== null;
|
||||
$hasUserInfo = $userInfo !== null;
|
||||
|
@ -78,13 +81,15 @@ class LoginAttempts {
|
|||
?bool $success = null,
|
||||
UserInfo|string|null $userInfo = null,
|
||||
IPAddress|string|null $remoteAddr = null,
|
||||
int|null $timeRange = null,
|
||||
TimeSpan|int|null $timeRange = null,
|
||||
?Pagination $pagination = null
|
||||
): iterable {
|
||||
if($userInfo instanceof UserInfo)
|
||||
$userInfo = $userInfo->getId();
|
||||
if($remoteAddr instanceof IPAddress)
|
||||
$remoteAddr = (string)$remoteAddr;
|
||||
if($timeRange instanceof TimeSpan)
|
||||
$timeRange = (int)$timeRange->totalSeconds();
|
||||
|
||||
$hasSuccess = $success !== null;
|
||||
$hasUserInfo = $userInfo !== null;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu\Auth;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
use Index\Net\IPAddress;
|
||||
|
||||
|
@ -36,16 +36,16 @@ class RecoveryTokenInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function getExpiresTime(): int {
|
||||
return $this->created + self::LIFETIME;
|
||||
}
|
||||
|
||||
public function getExpiresAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->getExpiresTime());
|
||||
public function getExpiresAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created + self::LIFETIME);
|
||||
}
|
||||
|
||||
public function hasExpired(): bool {
|
||||
|
|
|
@ -3,10 +3,10 @@ namespace Misuzu\Auth;
|
|||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Index\Base32;
|
||||
use Index\Data\DbStatementCache;
|
||||
use Index\Data\IDbConnection;
|
||||
use Index\Net\IPAddress;
|
||||
use Index\Serialisation\Base32;
|
||||
use Misuzu\ClientInfo;
|
||||
use Misuzu\Pagination;
|
||||
use Misuzu\Users\UserInfo;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?php
|
||||
namespace Misuzu\Auth;
|
||||
|
||||
use Misuzu\ClientInfo;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
use Index\Net\IPAddress;
|
||||
use Misuzu\ClientInfo;
|
||||
|
||||
class SessionInfo {
|
||||
public function __construct(
|
||||
|
@ -91,8 +91,8 @@ class SessionInfo {
|
|||
return $this->expires;
|
||||
}
|
||||
|
||||
public function getExpiresAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->expires);
|
||||
public function getExpiresAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->expires);
|
||||
}
|
||||
|
||||
public function shouldBumpExpires(): bool {
|
||||
|
@ -107,8 +107,8 @@ class SessionInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function hasLastActive(): bool {
|
||||
|
@ -119,7 +119,7 @@ class SessionInfo {
|
|||
return $this->lastActive;
|
||||
}
|
||||
|
||||
public function getLastActiveAt(): ?CarbonImmutable {
|
||||
return $this->lastActive === null ? null : CarbonImmutable::createFromTimestampUTC($this->lastActive);
|
||||
public function getLastActiveAt(): ?DateTime {
|
||||
return $this->lastActive === null ? null : DateTime::fromUnixTimeSeconds($this->lastActive);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu;
|
||||
|
||||
use Index\CSRFP;
|
||||
use Index\Security\CSRFP;
|
||||
|
||||
final class CSRF {
|
||||
private static CSRFP $instance;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu\Changelog;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
|
||||
class ChangeInfo {
|
||||
|
@ -53,8 +53,8 @@ class ChangeInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function getDate(): string {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
namespace Misuzu\Changelog;
|
||||
|
||||
use Stringable;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
|
||||
class ChangeTagInfo implements Stringable {
|
||||
|
@ -38,16 +38,16 @@ class ChangeTagInfo implements Stringable {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function getArchivedTime(): int {
|
||||
return $this->archived;
|
||||
}
|
||||
|
||||
public function getArchivedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->archived);
|
||||
public function getArchivedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function isArchived(): bool {
|
||||
|
|
|
@ -3,7 +3,7 @@ namespace Misuzu\Changelog;
|
|||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use DateTimeInterface;
|
||||
use Index\DateTime;
|
||||
use Index\Data\DbStatementCache;
|
||||
use Index\Data\DbTools;
|
||||
use Index\Data\IDbConnection;
|
||||
|
@ -66,13 +66,13 @@ class Changelog {
|
|||
|
||||
public function countChanges(
|
||||
UserInfo|string|null $userInfo = null,
|
||||
DateTimeInterface|int|null $dateTime = null,
|
||||
DateTime|int|null $dateTime = null,
|
||||
?array $tags = null
|
||||
): int {
|
||||
if($userInfo instanceof UserInfo)
|
||||
$userInfo = $userInfo->getId();
|
||||
if($dateTime instanceof DateTimeInterface)
|
||||
$dateTime = (int)$dateTime->format('U');
|
||||
if($dateTime instanceof DateTime)
|
||||
$dateTime = $dateTime->getUnixTimeSeconds();
|
||||
|
||||
$args = 0;
|
||||
$hasUserInfo = $userInfo !== null;
|
||||
|
@ -118,14 +118,14 @@ class Changelog {
|
|||
|
||||
public function getChanges(
|
||||
UserInfo|string|null $userInfo = null,
|
||||
DateTimeInterface|int|null $dateTime = null,
|
||||
DateTime|int|null $dateTime = null,
|
||||
?array $tags = null,
|
||||
?Pagination $pagination = null
|
||||
): iterable {
|
||||
if($userInfo instanceof UserInfo)
|
||||
$userInfo = $userInfo->getId();
|
||||
if($dateTime instanceof DateTimeInterface)
|
||||
$dateTime = (int)$dateTime->format('U');
|
||||
if($dateTime instanceof DateTime)
|
||||
$dateTime = $dateTime->getUnixTimeSeconds();
|
||||
|
||||
$args = 0;
|
||||
$hasUserInfo = $userInfo !== null;
|
||||
|
@ -189,14 +189,14 @@ class Changelog {
|
|||
string $summary,
|
||||
string $body = '',
|
||||
UserInfo|string|null $userInfo = null,
|
||||
DateTimeInterface|int|null $createdAt = null
|
||||
DateTime|int|null $createdAt = null
|
||||
): ChangeInfo {
|
||||
if(is_string($action))
|
||||
$action = self::convertToActionId($action);
|
||||
if($userInfo instanceof UserInfo)
|
||||
$userInfo = $userInfo->getId();
|
||||
if($createdAt instanceof DateTimeInterface)
|
||||
$createdAt = (int)$createdAt->format('U');
|
||||
if($createdAt instanceof DateTime)
|
||||
$createdAt = $createdAt->getUnixTimeSeconds();
|
||||
|
||||
$summary = trim($summary);
|
||||
if(empty($summary))
|
||||
|
@ -233,7 +233,7 @@ class Changelog {
|
|||
?string $body = null,
|
||||
bool $updateUserInfo = false,
|
||||
UserInfo|string|null $userInfo = null,
|
||||
DateTimeInterface|int|null $createdAt = null
|
||||
DateTime|int|null $createdAt = null
|
||||
): void {
|
||||
if($infoOrId instanceof ChangeInfo)
|
||||
$infoOrId = $infoOrId->getId();
|
||||
|
@ -242,8 +242,8 @@ class Changelog {
|
|||
$action = self::convertToActionId($action);
|
||||
if($userInfo instanceof UserInfo)
|
||||
$userInfo = $userInfo->getId();
|
||||
if($createdAt instanceof DateTimeInterface)
|
||||
$createdAt = (int)$createdAt->format('U');
|
||||
if($createdAt instanceof DateTime)
|
||||
$createdAt = $createdAt->getUnixTimeSeconds();
|
||||
|
||||
if($summary !== null) {
|
||||
$summary = trim($summary);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
namespace Misuzu\Comments;
|
||||
|
||||
use Misuzu\Users\UserInfo;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
use Misuzu\Users\UserInfo;
|
||||
|
||||
class CommentsCategoryInfo {
|
||||
public function __construct(
|
||||
|
@ -54,17 +54,16 @@ class CommentsCategoryInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function getLockedTime(): ?int {
|
||||
return $this->locked;
|
||||
}
|
||||
|
||||
public function getLockedAt(): ?CarbonImmutable {
|
||||
return $this->locked === null ? null : CarbonImmutable::createFromTimestampUTC($this->locked);
|
||||
public function getLockedAt(): ?DateTime {
|
||||
return $this->locked === null ? null : DateTime::fromUnixTimeSeconds($this->locked);
|
||||
}
|
||||
|
||||
public function isLocked(): bool {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu\Comments;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
|
||||
class CommentsPostInfo {
|
||||
|
@ -86,16 +86,16 @@ class CommentsPostInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function getPinnedTime(): ?int {
|
||||
return $this->pinned;
|
||||
}
|
||||
|
||||
public function getPinnedAt(): ?CarbonImmutable {
|
||||
return $this->pinned === null ? null : CarbonImmutable::createFromTimestampUTC($this->pinned);
|
||||
public function getPinnedAt(): DateTime {
|
||||
return $this->pinned === null ? null : DateTime::fromUnixTimeSeconds($this->pinned);
|
||||
}
|
||||
|
||||
public function isPinned(): bool {
|
||||
|
@ -106,8 +106,8 @@ class CommentsPostInfo {
|
|||
return $this->updated;
|
||||
}
|
||||
|
||||
public function getUpdatedAt(): ?CarbonImmutable {
|
||||
return $this->updated === null ? null : CarbonImmutable::createFromTimestampUTC($this->updated);
|
||||
public function getUpdatedAt(): DateTime {
|
||||
return $this->updated === null ? null : DateTime::fromUnixTimeSeconds($this->updated);
|
||||
}
|
||||
|
||||
public function isEdited(): bool {
|
||||
|
@ -118,8 +118,8 @@ class CommentsPostInfo {
|
|||
return $this->deleted;
|
||||
}
|
||||
|
||||
public function getDeletedAt(): ?CarbonImmutable {
|
||||
return $this->deleted === null ? null : CarbonImmutable::createFromTimestampUTC($this->deleted);
|
||||
public function getDeletedAt(): DateTime {
|
||||
return $this->deleted === null ? null : DateTime::fromUnixTimeSeconds($this->deleted);
|
||||
}
|
||||
|
||||
public function isDeleted(): bool {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu\Counters;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
|
||||
class CounterInfo {
|
||||
|
@ -31,7 +31,7 @@ class CounterInfo {
|
|||
return $this->updated;
|
||||
}
|
||||
|
||||
public function getUpdatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->updated);
|
||||
public function getUpdatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->updated);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu\Forum;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Colour\Colour;
|
||||
use Index\Data\IDbResult;
|
||||
|
||||
|
@ -176,8 +176,8 @@ class ForumCategoryInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function isArchived(): bool {
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
<?php
|
||||
namespace Misuzu\Forum;
|
||||
|
||||
use Misuzu\Parsers\Parser;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\XDateTime;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
use Index\Net\IPAddress;
|
||||
use Misuzu\Parsers\Parser;
|
||||
|
||||
class ForumPostInfo {
|
||||
public function __construct(
|
||||
|
@ -94,17 +93,16 @@ class ForumPostInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
private static ?CarbonImmutable $markAsEditedThreshold = null;
|
||||
|
||||
private static ?DateTime $markAsEditedThreshold = null;
|
||||
public function shouldMarkAsEdited(): bool {
|
||||
if(self::$markAsEditedThreshold === null)
|
||||
self::$markAsEditedThreshold = new CarbonImmutable('-5 minutes');
|
||||
self::$markAsEditedThreshold = DateTime::now()->modify('-5 minutes');
|
||||
|
||||
return XDateTime::compare($this->getCreatedAt(), self::$markAsEditedThreshold) < 0;
|
||||
return $this->getCreatedAt()->isLessThan(self::$markAsEditedThreshold);
|
||||
}
|
||||
|
||||
public function isEdited(): bool {
|
||||
|
@ -115,17 +113,16 @@ class ForumPostInfo {
|
|||
return $this->edited;
|
||||
}
|
||||
|
||||
public function getEditedAt(): ?CarbonImmutable {
|
||||
return $this->edited === null ? null : CarbonImmutable::createFromTimestampUTC($this->edited);
|
||||
public function getEditedAt(): ?DateTime {
|
||||
return $this->edited === null ? null : DateTime::fromUnixTimeSeconds($this->edited);
|
||||
}
|
||||
|
||||
private static ?CarbonImmutable $canBeDeletedThreshold = null;
|
||||
|
||||
private static ?DateTime $canBeDeletedThreshold = null;
|
||||
public function canBeDeleted(): bool {
|
||||
if(self::$canBeDeletedThreshold === null)
|
||||
self::$canBeDeletedThreshold = new CarbonImmutable('-1 week');
|
||||
self::$canBeDeletedThreshold = DateTime::now()->modify('-1 week');
|
||||
|
||||
return XDateTime::compare($this->getCreatedAt(), self::$canBeDeletedThreshold) >= 0;
|
||||
return $this->getCreatedAt()->isMoreThanOrEqual(self::$canBeDeletedThreshold);
|
||||
}
|
||||
|
||||
public function isDeleted(): bool {
|
||||
|
@ -136,7 +133,7 @@ class ForumPostInfo {
|
|||
return $this->deleted;
|
||||
}
|
||||
|
||||
public function getDeletedAt(): ?CarbonImmutable {
|
||||
return $this->deleted === null ? null : CarbonImmutable::createFromTimestampUTC($this->deleted);
|
||||
public function getDeletedAt(): ?DateTime {
|
||||
return $this->deleted === null ? null : DateTime::fromUnixTimeSeconds($this->deleted);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace Misuzu\Forum;
|
|||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use stdClass;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\DbStatementCache;
|
||||
use Index\Data\DbTools;
|
||||
use Index\Data\IDbConnection;
|
||||
|
@ -395,8 +395,8 @@ class ForumPosts {
|
|||
return $result->getInteger(0);
|
||||
}
|
||||
|
||||
public function getUserLastPostCreatedAt(UserInfo|string $userInfo): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->getUserLastPostCreatedTime($userInfo));
|
||||
public function getUserLastPostCreatedAt(UserInfo|string $userInfo): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->getUserLastPostCreatedTime($userInfo));
|
||||
}
|
||||
|
||||
public function generatePostRankings(
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu\Forum;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\XDateTime;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
|
||||
class ForumTopicInfo {
|
||||
|
@ -137,25 +136,25 @@ class ForumTopicInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
private static ?CarbonImmutable $lastActiveAt = null;
|
||||
private static ?DateTime $lastActiveAt = null;
|
||||
|
||||
public function isActive(): bool {
|
||||
if(self::$lastActiveAt === null)
|
||||
self::$lastActiveAt = new CarbonImmutable('-1 month');
|
||||
self::$lastActiveAt = DateTime::now()->modify('-1 month');
|
||||
|
||||
return XDateTime::compare($this->getBumpedAt(), self::$lastActiveAt) >= 0;
|
||||
return $this->getBumpedAt()->isMoreThanOrEqual(self::$lastActiveAt);
|
||||
}
|
||||
|
||||
public function getBumpedTime(): int {
|
||||
return $this->bumped;
|
||||
}
|
||||
|
||||
public function getBumpedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->bumped);
|
||||
public function getBumpedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->bumped);
|
||||
}
|
||||
|
||||
public function isDeleted(): bool {
|
||||
|
@ -166,8 +165,8 @@ class ForumTopicInfo {
|
|||
return $this->deleted;
|
||||
}
|
||||
|
||||
public function getDeletedAt(): ?CarbonImmutable {
|
||||
return $this->deleted === null ? null : CarbonImmutable::createFromTimestampUTC($this->deleted);
|
||||
public function getDeletedAt(): ?DateTime {
|
||||
return $this->deleted === null ? null : DateTime::fromUnixTimeSeconds($this->deleted);
|
||||
}
|
||||
|
||||
public function isLocked(): bool {
|
||||
|
@ -178,7 +177,7 @@ class ForumTopicInfo {
|
|||
return $this->locked;
|
||||
}
|
||||
|
||||
public function getLockedAt(): ?CarbonImmutable {
|
||||
return $this->locked === null ? null : CarbonImmutable::createFromTimestampUTC($this->locked);
|
||||
public function getLockedAt(): ?DateTime {
|
||||
return $this->locked === null ? null : DateTime::fromUnixTimeSeconds($this->locked);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu\Forum;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
|
||||
class ForumTopicRedirectInfo {
|
||||
|
@ -41,7 +41,7 @@ class ForumTopicRedirectInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,49 @@
|
|||
<?php
|
||||
namespace Misuzu\Hanyuu;
|
||||
|
||||
use stdClass;
|
||||
use RuntimeException;
|
||||
use Index\Colour\Colour;
|
||||
use Index\Http\Routing\{HttpGet,HttpMiddleware,HttpPost,RouteHandler};
|
||||
use Index\Serialisation\UriBase64;
|
||||
use Syokuhou\IConfig;
|
||||
use Misuzu\CSRF;
|
||||
use Misuzu\Auth\AuthContext;
|
||||
use Misuzu\Auth\{AuthContext,AuthInfo,Sessions};
|
||||
use Misuzu\URLs\URLRegistry;
|
||||
use Misuzu\Users\{UsersContext,UserInfo};
|
||||
use Aiwass\Server\{RpcActionHandler,RpcProcedure};
|
||||
use Index\Colour\Colour;
|
||||
use Syokuhou\IConfig;
|
||||
|
||||
final class HanyuuRpcActions extends RpcActionHandler {
|
||||
final class HanyuuRoutes extends RouteHandler {
|
||||
public function __construct(
|
||||
private $getBaseUrl,
|
||||
private IConfig $impersonateConfig,
|
||||
private IConfig $config,
|
||||
private IConfig $impersonateConfig, // this sucks lol
|
||||
private URLRegistry $urls,
|
||||
private UsersContext $usersCtx,
|
||||
private AuthContext $authCtx
|
||||
private AuthContext $authCtx,
|
||||
private AuthInfo $authInfo
|
||||
) {}
|
||||
|
||||
private static function createPayload(string $name, array $attrs = []): array {
|
||||
$payload = ['name' => $name, 'attrs' => []];
|
||||
private function getEndpoint(): string {
|
||||
return $this->config->getString('endpoint');
|
||||
}
|
||||
|
||||
private function getSecret(): string {
|
||||
return $this->config->getString('secret');
|
||||
}
|
||||
|
||||
private static function createPayload(string $name, array $attrs = []): object {
|
||||
$payload = new stdClass;
|
||||
$payload->name = $name;
|
||||
$payload->attrs = [];
|
||||
foreach($attrs as $name => $value) {
|
||||
if($value === null)
|
||||
continue;
|
||||
$payload['attrs'][(string)$name] = $value;
|
||||
$payload->attrs[(string)$name] = $value;
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
private static function createErrorPayload(string $code, ?string $text = null): array {
|
||||
private static function createErrorPayload(string $code, ?string $text = null): object {
|
||||
$attrs = ['code' => $code];
|
||||
if($text !== null && $text !== '')
|
||||
$attrs['text'] = $text;
|
||||
|
@ -38,6 +51,42 @@ final class HanyuuRpcActions extends RpcActionHandler {
|
|||
return self::createPayload('error', $attrs);
|
||||
}
|
||||
|
||||
#[HttpMiddleware('/_hanyuu/(.*)')]
|
||||
public function verifyRequest($response, $request, string $action) {
|
||||
$userTime = (int)$request->getHeaderLine('X-Hanyuu-Timestamp');
|
||||
$userHash = UriBase64::decode((string)$request->getHeaderLine('X-Hanyuu-Signature'));
|
||||
|
||||
$currentTime = time();
|
||||
if(empty($userHash) || $userTime < $currentTime - 60 || $userTime > $currentTime + 60)
|
||||
return self::createErrorPayload('verification', 'Request verification failed.');
|
||||
|
||||
$url = sprintf('%s/_hanyuu/%s', $this->getEndpoint(), $action);
|
||||
$params = $request->getParamString();
|
||||
if($params !== '')
|
||||
$url .= sprintf('?%s', $params);
|
||||
|
||||
if($request->getMethod() === 'POST') {
|
||||
if(!$request->isFormContent())
|
||||
return self::createErrorPayload('request', 'Request body is not in expect format.');
|
||||
|
||||
$body = $request->getContent()->getParamString();
|
||||
} elseif($request->getMethod() !== 'GET') {
|
||||
return self::createErrorPayload('request', 'Only GET and POST methods are allowed.');
|
||||
} else {
|
||||
$body = '';
|
||||
}
|
||||
|
||||
$verifyHash = hash_hmac(
|
||||
'sha256',
|
||||
sprintf('[%s|%s|%s]', $userTime, $url, $body),
|
||||
$this->getSecret(),
|
||||
true
|
||||
);
|
||||
|
||||
if(!hash_equals($verifyHash, $userHash))
|
||||
return self::createErrorPayload('verification', 'Request verification failed.');
|
||||
}
|
||||
|
||||
private function canImpersonateUserId(UserInfo $impersonator, string $targetId): bool {
|
||||
if($impersonator->isSuperUser())
|
||||
return true;
|
||||
|
@ -49,15 +98,18 @@ final class HanyuuRpcActions extends RpcActionHandler {
|
|||
);
|
||||
}
|
||||
|
||||
#[RpcProcedure('mszhau:authCheck')]
|
||||
public function procAuthCheck(string $method, string $remoteAddr, string $token, string $avatars = '') {
|
||||
#[HttpPost('/_hanyuu/auth-check')]
|
||||
public function postCheckAuth($response, $request) {
|
||||
$content = $request->getContent();
|
||||
$method = (string)$content->getParam('method');
|
||||
if($method !== 'Misuzu')
|
||||
return self::createErrorPayload('auth:check:method', 'Requested auth method is not supported.');
|
||||
|
||||
$remoteAddr = (string)$content->getParam('remote_addr');
|
||||
if(filter_var($remoteAddr, FILTER_VALIDATE_IP) === false)
|
||||
return self::createErrorPayload('auth:check:remote_addr', 'Provided remote address is not in a valid format.');
|
||||
|
||||
$avatarResolutions = trim($avatars);
|
||||
$avatarResolutions = trim((string)$content->getParam('avatars'));
|
||||
if($avatarResolutions === '') {
|
||||
$avatarResolutions = [];
|
||||
} else {
|
||||
|
@ -70,12 +122,11 @@ final class HanyuuRpcActions extends RpcActionHandler {
|
|||
$avatarResolutions = array_unique($avatarResolutions);
|
||||
}
|
||||
|
||||
$baseUrl = ($this->getBaseUrl)();
|
||||
$loginUrl = $baseUrl . $this->urls->format('auth-login');
|
||||
$registerUrl = $baseUrl . $this->urls->format('auth-register');
|
||||
$loginUrl = $this->getEndpoint() . $this->urls->format('auth-login');
|
||||
$registerUrl = $this->getEndpoint() . $this->urls->format('auth-register');
|
||||
|
||||
$tokenPacker = $this->authCtx->createAuthTokenPacker();
|
||||
$tokenInfo = $tokenPacker->unpack(trim($token));
|
||||
$tokenInfo = $tokenPacker->unpack(trim((string)$content->getParam('token')));
|
||||
if($tokenInfo->isEmpty())
|
||||
return self::createPayload('auth:check:fail', ['reason' => 'empty', 'login_url' => $loginUrl, 'register_url' => $registerUrl]);
|
||||
|
||||
|
@ -105,7 +156,6 @@ final class HanyuuRpcActions extends RpcActionHandler {
|
|||
|
||||
$response = [];
|
||||
$response['session'] = [
|
||||
'token' => $sessionInfo->getToken(),
|
||||
'created_at' => $sessionInfo->getCreatedTime(),
|
||||
'expires_at' => $sessionInfo->getExpiresTime(),
|
||||
'lifetime_extends' => $sessionInfo->shouldBumpExpires(),
|
||||
|
@ -123,9 +173,9 @@ final class HanyuuRpcActions extends RpcActionHandler {
|
|||
'remaining_str' => $banInfo->getRemainingString(),
|
||||
];
|
||||
|
||||
$gatherRequestedAvatars = function($userInfo) use ($avatarResolutions, $baseUrl) {
|
||||
$gatherRequestedAvatars = function($userInfo) use ($avatarResolutions) {
|
||||
$formatAvatarUrl = fn($res = 0) => (
|
||||
$baseUrl . $this->urls->format('user-avatar', ['user' => $userInfo->getId(), 'res' => $res])
|
||||
$this->getEndpoint() . $this->urls->format('user-avatar', ['user' => $userInfo->getId(), 'res' => $res])
|
||||
);
|
||||
|
||||
$avatars = ['original' => $formatAvatarUrl()];
|
||||
|
@ -145,7 +195,7 @@ final class HanyuuRpcActions extends RpcActionHandler {
|
|||
'country_code' => $userInfo->getCountryCode(),
|
||||
'is_deleted' => $userInfo->isDeleted(),
|
||||
'has_totp' => $userInfo->hasTOTPKey(),
|
||||
'profile_url' => $baseUrl . $this->urls->format('user-profile', ['user' => $userInfo->getId()]),
|
||||
'profile_url' => $this->getEndpoint() . $this->urls->format('user-profile', ['user' => $userInfo->getId()]),
|
||||
'avatars' => $gatherRequestedAvatars($userInfo),
|
||||
];
|
||||
|
||||
|
@ -154,7 +204,7 @@ final class HanyuuRpcActions extends RpcActionHandler {
|
|||
$response['guise'] = $extractUserInfo($userInfoReal);
|
||||
|
||||
$csrfp = CSRF::create($sessionInfo->getToken());
|
||||
$response['guise']['revert_url'] = $baseUrl . $this->urls->format('auth-revert', ['csrf' => $csrfp->createToken()]);
|
||||
$response['guise']['revert_url'] = $this->getEndpoint() . $this->urls->format('auth-revert', ['csrf' => $csrfp->createToken()]);
|
||||
}
|
||||
|
||||
return self::createPayload('auth:check:success', $response);
|
|
@ -2,7 +2,7 @@
|
|||
namespace Misuzu\Home;
|
||||
|
||||
use RuntimeException;
|
||||
use Index\XDateTime;
|
||||
use Index\DateTime;
|
||||
use Index\Data\{DbTools,IDbConnection};
|
||||
use Index\Http\Routing\{HttpGet,RouteHandler};
|
||||
use Syokuhou\IConfig;
|
||||
|
@ -167,7 +167,7 @@ class HomeRoutes extends RouteHandler {
|
|||
$stats['users:online:recent'] = count($onlineUserInfos);
|
||||
|
||||
$birthdays = [];
|
||||
$birthdayInfos = $this->usersCtx->getUsers()->getUsers(deleted: false, birthdate: XDateTime::now(), orderBy: 'random');
|
||||
$birthdayInfos = $this->usersCtx->getUsers()->getUsers(deleted: false, birthdate: DateTime::now(), orderBy: 'random');
|
||||
foreach($birthdayInfos as $birthdayInfo)
|
||||
$birthdays[] = [
|
||||
'info' => $birthdayInfo,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?php
|
||||
namespace Misuzu\Messages;
|
||||
|
||||
use Misuzu\Parsers\Parser;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
use Misuzu\Parsers\Parser;
|
||||
|
||||
class MessageInfo {
|
||||
public function __construct(
|
||||
|
@ -98,8 +98,8 @@ class MessageInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function isSent(): bool {
|
||||
|
@ -110,8 +110,8 @@ class MessageInfo {
|
|||
return $this->sent;
|
||||
}
|
||||
|
||||
public function getSentAt(): ?CarbonImmutable {
|
||||
return $this->sent === null ? null : CarbonImmutable::createFromTimestampUTC($this->sent);
|
||||
public function getSentAt(): ?DateTime {
|
||||
return $this->sent === null ? null : DateTime::fromUnixTimeSeconds($this->sent);
|
||||
}
|
||||
|
||||
public function isRead(): bool {
|
||||
|
@ -122,8 +122,8 @@ class MessageInfo {
|
|||
return $this->read;
|
||||
}
|
||||
|
||||
public function getReadAt(): ?CarbonImmutable {
|
||||
return $this->read === null ? null : CarbonImmutable::createFromTimestampUTC($this->read);
|
||||
public function getReadAt(): ?DateTime {
|
||||
return $this->read === null ? null : DateTime::fromUnixTimeSeconds($this->read);
|
||||
}
|
||||
|
||||
public function isDeleted(): bool {
|
||||
|
@ -134,8 +134,8 @@ class MessageInfo {
|
|||
return $this->deleted;
|
||||
}
|
||||
|
||||
public function getDeletedAt(): ?CarbonImmutable {
|
||||
return $this->deleted === null ? null : CarbonImmutable::createFromTimestampUTC($this->deleted);
|
||||
public function getDeletedAt(): ?DateTime {
|
||||
return $this->deleted === null ? null : DateTime::fromUnixTimeSeconds($this->deleted);
|
||||
}
|
||||
|
||||
public function getDisplayTime(): int {
|
||||
|
@ -144,7 +144,7 @@ class MessageInfo {
|
|||
return $this->getCreatedTime();
|
||||
}
|
||||
|
||||
public function getDisplayAt(): CarbonImmutable {
|
||||
public function getDisplayAt(): DateTime {
|
||||
if($this->isSent())
|
||||
return $this->getSentAt();
|
||||
return $this->getCreatedAt();
|
||||
|
|
|
@ -3,7 +3,7 @@ namespace Misuzu\Messages;
|
|||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use DateTimeInterface;
|
||||
use Index\DateTime;
|
||||
use Index\Data\{DbStatementCache,DbTools,IDbConnection};
|
||||
use Misuzu\Pagination;
|
||||
use Misuzu\Users\UserInfo;
|
||||
|
@ -189,8 +189,8 @@ class MessagesDatabase {
|
|||
string $body,
|
||||
int $parser,
|
||||
MessageInfo|string|null $replyTo = null,
|
||||
DateTimeInterface|int|null $sentAt = null,
|
||||
DateTimeInterface|int|null $readAt = null
|
||||
DateTime|int|null $sentAt = null,
|
||||
DateTime|int|null $readAt = null
|
||||
): MessageInfo {
|
||||
$stmt = $this->cache->get('INSERT INTO msz_messages (msg_id, msg_owner_id, msg_author_id, msg_recipient_id, msg_reply_to, msg_title, msg_body, msg_parser, msg_sent, msg_read) VALUES (?, ?, ?, ?, ?, TO_BASE64(?), TO_BASE64(?), ?, FROM_UNIXTIME(?), FROM_UNIXTIME(?))');
|
||||
$stmt->addParameter(1, $messageId);
|
||||
|
@ -201,8 +201,8 @@ class MessagesDatabase {
|
|||
$stmt->addParameter(6, $title);
|
||||
$stmt->addParameter(7, $body);
|
||||
$stmt->addParameter(8, $parser);
|
||||
$stmt->addParameter(9, $sentAt instanceof DateTimeInterface ? (int)$sentAt->format('U') : $sentAt);
|
||||
$stmt->addParameter(10, $readAt instanceof DateTimeInterface ? (int)$readAt->format('U') : $readAt);
|
||||
$stmt->addParameter(9, $sentAt instanceof DateTime ? $sentAt->getUnixTimeSeconds() : $sentAt);
|
||||
$stmt->addParameter(10, $readAt instanceof DateTime ? $readAt->getUnixTimeSeconds() : $readAt);
|
||||
$stmt->execute();
|
||||
|
||||
return $this->getMessageInfo($ownerInfo, $messageId);
|
||||
|
@ -214,8 +214,8 @@ class MessagesDatabase {
|
|||
?string $title = null,
|
||||
?string $body = null,
|
||||
?int $parser = null,
|
||||
DateTimeInterface|int|null|false $sentAt = false,
|
||||
DateTimeInterface|int|null|false $readAt = false
|
||||
DateTime|int|null|false $sentAt = false,
|
||||
DateTime|int|null|false $readAt = false
|
||||
): void {
|
||||
$setQuery = [];
|
||||
$setValues = [];
|
||||
|
@ -249,12 +249,12 @@ class MessagesDatabase {
|
|||
|
||||
if($sentAt !== false) {
|
||||
$setQuery[] = 'msg_sent = FROM_UNIXTIME(?)';
|
||||
$setValues[] = $sentAt instanceof DateTimeInterface ? (int)$sentAt->format('U') : $sentAt;
|
||||
$setValues[] = $sentAt instanceof DateTime ? $sentAt->getUnixTimeSeconds() : $sentAt;
|
||||
}
|
||||
|
||||
if($readAt !== false) {
|
||||
$setQuery[] = 'msg_read = FROM_UNIXTIME(?)';
|
||||
$setValues[] = $readAt instanceof DateTimeInterface ? (int)$readAt->format('U') : $readAt;
|
||||
$setValues[] = $readAt instanceof DateTime ? $readAt->getUnixTimeSeconds() : $readAt;
|
||||
}
|
||||
|
||||
if(empty($whereQuery))
|
||||
|
|
|
@ -357,6 +357,7 @@ class MessagesRoutes extends RouteHandler {
|
|||
'error' => [
|
||||
'name' => 'msgs:recipient_invalid',
|
||||
'text' => 'Name of the recipient was incorrectly formatted.',
|
||||
'jeff' => $recipient,
|
||||
],
|
||||
];
|
||||
} catch(RuntimeException $ex) {
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
<?php
|
||||
namespace Misuzu;
|
||||
|
||||
use Index\Environment;
|
||||
use Index\Data\IDbConnection;
|
||||
use Index\Data\Migration\{IDbMigrationRepo,DbMigrationManager,FsDbMigrationRepo};
|
||||
use Sasae\SasaeEnvironment;
|
||||
use Syokuhou\IConfig;
|
||||
use Misuzu\Template;
|
||||
use Misuzu\Auth\{AuthContext,AuthInfo};
|
||||
use Misuzu\AuditLog\AuditLog;
|
||||
|
@ -15,12 +20,6 @@ use Misuzu\Perms\Permissions;
|
|||
use Misuzu\Profile\ProfileFields;
|
||||
use Misuzu\URLs\URLRegistry;
|
||||
use Misuzu\Users\{UsersContext,UserInfo};
|
||||
use Aiwass\HmacVerificationProvider;
|
||||
use Aiwass\Server\RpcServer;
|
||||
use Index\Data\IDbConnection;
|
||||
use Index\Data\Migration\{IDbMigrationRepo,DbMigrationManager,FsDbMigrationRepo};
|
||||
use Sasae\SasaeEnvironment;
|
||||
use Syokuhou\IConfig;
|
||||
|
||||
// this class should function as the root for everything going forward
|
||||
// no more magical static classes that are just kind of assumed to exist
|
||||
|
@ -192,7 +191,7 @@ class MisuzuContext {
|
|||
['eeprom.appmsgs:s', '', 'eeprom_app_messages'],
|
||||
]);
|
||||
|
||||
$isDebug = MSZ_DEBUG;
|
||||
$isDebug = Environment::isDebug();
|
||||
$globals['site_info'] = $this->siteInfo;
|
||||
$globals['auth_info'] = $this->authInfo;
|
||||
$globals['active_ban_info'] = $this->usersCtx->tryGetActiveBan($this->authInfo->getUserInfo());
|
||||
|
@ -279,39 +278,17 @@ class MisuzuContext {
|
|||
$this->profileFields
|
||||
));
|
||||
|
||||
$routingCtx->register(new \Misuzu\Hanyuu\HanyuuRoutes(
|
||||
$this->config->scopeTo('hanyuu'),
|
||||
$this->config->scopeTo('impersonate'),
|
||||
$this->urls,
|
||||
$this->usersCtx,
|
||||
$this->authCtx,
|
||||
$this->authInfo
|
||||
));
|
||||
|
||||
$routingCtx->register(new LegacyRoutes($this->urls));
|
||||
|
||||
$rpcServer = new RpcServer;
|
||||
$routingCtx->getRouter()->register($rpcServer->createRouteHandler(
|
||||
new HmacVerificationProvider(fn() => $this->config->getString('aleister.secret'))
|
||||
));
|
||||
|
||||
$rpcServer->register(new Auth\AuthRpcActions(
|
||||
$this->config->scopeTo('impersonate'),
|
||||
$this->usersCtx,
|
||||
$this->authCtx
|
||||
));
|
||||
|
||||
$rpcServer->register(new Users\UsersRpcActions(
|
||||
$this->siteInfo,
|
||||
$this->urls,
|
||||
$this->usersCtx
|
||||
));
|
||||
|
||||
// This RPC server will eventually despawn when Hanyuu fully owns auth
|
||||
$hanyuuRpcServer = new RpcServer;
|
||||
$routingCtx->getRouter()->scopeTo('/_hanyuu')->register($hanyuuRpcServer->createRouteHandler(
|
||||
new HmacVerificationProvider(fn() => $this->config->getString('hanyuu.secret'))
|
||||
));
|
||||
|
||||
$hanyuuRpcServer->register(new Hanyuu\HanyuuRpcActions(
|
||||
fn() => $this->config->getString('hanyuu.endpoint'),
|
||||
$this->config->scopeTo('impersonate'),
|
||||
$this->urls,
|
||||
$this->usersCtx,
|
||||
$this->authCtx
|
||||
));
|
||||
|
||||
return $routingCtx;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
<?php
|
||||
namespace Misuzu;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Index\DateTime;
|
||||
use Misuzu\MisuzuContext;
|
||||
use Misuzu\Tools;
|
||||
use Misuzu\Parsers\Parser;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
use Twig\TwigFunction;
|
||||
|
@ -47,18 +46,30 @@ final class MisuzuSasaeExtension extends AbstractExtension {
|
|||
return $this->assets?->{$name} ?? '';
|
||||
}
|
||||
|
||||
public function timeFormat(DateTimeInterface|string|int|null $dateTime): string {
|
||||
public function timeFormat(DateTime|string|int|null $dateTime): string {
|
||||
if($dateTime === null)
|
||||
return 'never';
|
||||
|
||||
if(is_string($dateTime))
|
||||
$dateTime = new CarbonImmutable($dateTime);
|
||||
$dateTime = new DateTime($dateTime);
|
||||
elseif(is_int($dateTime))
|
||||
$dateTime = CarbonImmutable::createFromTimestampUTC($dateTime);
|
||||
elseif(!($dateTime instanceof CarbonImmutable))
|
||||
$dateTime = new CarbonImmutable($dateTime);
|
||||
$dateTime = DateTime::fromUnixTimeSeconds($dateTime);
|
||||
|
||||
return $dateTime->diffForHumans();
|
||||
$string = '';
|
||||
$now = DateTime::now();
|
||||
|
||||
$isDiffYear = $now->getYear() !== $dateTime->getYear();
|
||||
if($isDiffYear || $now->getMonth() !== $dateTime->getMonth() || $now->getDay() !== $dateTime->getDay()) {
|
||||
$string .= $dateTime->format('M jS');
|
||||
if($isDiffYear)
|
||||
$string .= $dateTime->format(' Y');
|
||||
$string .= ', ';
|
||||
}
|
||||
|
||||
$string .= $dateTime->format('G:i ');
|
||||
$string .= $dateTime->isUTC() ? 'UTC' : $dateTime->format('T');
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
public function getHeaderMenu(): array {
|
||||
|
|
|
@ -3,7 +3,7 @@ namespace Misuzu\News;
|
|||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use DateTimeInterface;
|
||||
use Index\DateTime;
|
||||
use Index\Data\DbStatementCache;
|
||||
use Index\Data\IDbConnection;
|
||||
use Index\Data\IDbResult;
|
||||
|
@ -286,14 +286,14 @@ class News {
|
|||
string $body,
|
||||
bool $featured = false,
|
||||
UserInfo|string|null $userInfo = null,
|
||||
DateTimeInterface|int|null $schedule = null
|
||||
DateTime|int|null $schedule = null
|
||||
): NewsPostInfo {
|
||||
if($categoryInfo instanceof NewsCategoryInfo)
|
||||
$categoryInfo = $categoryInfo->getId();
|
||||
if($userInfo instanceof UserInfo)
|
||||
$userInfo = $userInfo->getId();
|
||||
if($schedule instanceof DateTimeInterface)
|
||||
$schedule = (int)$schedule->format('U');
|
||||
if($schedule instanceof DateTime)
|
||||
$schedule = $schedule->getUnixTimeSeconds();
|
||||
|
||||
$title = trim($title);
|
||||
if(empty($title))
|
||||
|
@ -351,7 +351,7 @@ class News {
|
|||
?bool $featured = null,
|
||||
bool $updateUserInfo = false,
|
||||
UserInfo|string|null $userInfo = null,
|
||||
DateTimeInterface|int|null $schedule = null
|
||||
DateTime|int|null $schedule = null
|
||||
): void {
|
||||
if($postInfo instanceof NewsPostInfo)
|
||||
$postInfo = $postInfo->getId();
|
||||
|
@ -359,8 +359,8 @@ class News {
|
|||
$categoryInfo = $categoryInfo->getId();
|
||||
if($userInfo instanceof UserInfo)
|
||||
$userInfo = $userInfo->getId();
|
||||
if($schedule instanceof DateTimeInterface)
|
||||
$schedule = (int)$schedule->format('U');
|
||||
if($schedule instanceof DateTime)
|
||||
$schedule = $schedule->getUnixTimeSeconds();
|
||||
|
||||
if($title !== null) {
|
||||
$title = trim($title);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu\News;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
|
||||
class NewsCategoryInfo {
|
||||
|
@ -45,8 +45,8 @@ class NewsCategoryInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function getPostsCount(): int {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu\News;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
|
||||
class NewsPostInfo {
|
||||
|
@ -84,8 +84,8 @@ class NewsPostInfo {
|
|||
return $this->scheduled;
|
||||
}
|
||||
|
||||
public function getScheduledAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->scheduled);
|
||||
public function getScheduledAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->scheduled);
|
||||
}
|
||||
|
||||
public function isPublished(): bool {
|
||||
|
@ -96,16 +96,16 @@ class NewsPostInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function getUpdatedTime(): int {
|
||||
return $this->updated;
|
||||
}
|
||||
|
||||
public function getUpdatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->updated);
|
||||
public function getUpdatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->updated);
|
||||
}
|
||||
|
||||
public function isEdited(): bool {
|
||||
|
@ -120,7 +120,7 @@ class NewsPostInfo {
|
|||
return $this->deleted;
|
||||
}
|
||||
|
||||
public function getDeletedAt(): ?CarbonImmutable {
|
||||
return $this->deleted === null ? null : CarbonImmutable::createFromTimestampUTC($this->deleted);
|
||||
public function getDeletedAt(): ?DateTime {
|
||||
return $this->deleted === null ? null : DateTime::fromUnixTimeSeconds($this->deleted);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
namespace Misuzu\News;
|
||||
|
||||
use RuntimeException;
|
||||
use Index\DateTime;
|
||||
use Index\Data\{DbTools,IDbConnection};
|
||||
use Index\Http\Routing\{HttpGet,RouteHandler};
|
||||
use Misuzu\{Pagination,SiteInfo,Template};
|
||||
|
|
|
@ -4,7 +4,8 @@ namespace Misuzu\Perms;
|
|||
use stdClass;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Index\XDateTime;
|
||||
use Index\DateTime;
|
||||
use Index\Environment;
|
||||
use Index\Data\DbStatementCache;
|
||||
use Index\Data\DbTools;
|
||||
use Index\Data\IDbConnection;
|
||||
|
@ -370,10 +371,10 @@ class Permissions {
|
|||
}
|
||||
|
||||
private static function precalculatePermissionsLog(string $fmt, ...$args): void {
|
||||
if(!MSZ_CLI)
|
||||
if(!Environment::isConsole())
|
||||
return;
|
||||
|
||||
echo XDateTime::now()->format('[H:i:s.u] ');
|
||||
echo DateTime::now()->format('[H:i:s.u] ');
|
||||
vprintf($fmt, $args);
|
||||
echo PHP_EOL;
|
||||
}
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
namespace Misuzu\SharpChat;
|
||||
|
||||
use RuntimeException;
|
||||
use Index\Colour\Colour;
|
||||
use Index\Http\Routing\{HandlerAttribute,HttpDelete,HttpGet,HttpOptions,HttpPost,RouteHandler};
|
||||
use Syokuhou\IConfig;
|
||||
use Misuzu\RoutingContext;
|
||||
use Misuzu\Auth\{AuthContext,AuthInfo,Sessions};
|
||||
use Misuzu\Emoticons\Emotes;
|
||||
use Misuzu\Perms\Permissions;
|
||||
use Misuzu\URLs\URLRegistry;
|
||||
use Misuzu\Users\{Bans,UsersContext,UserInfo};
|
||||
use Index\Colour\Colour;
|
||||
use Index\Http\Routing\{HandlerAttribute,HttpDelete,HttpGet,HttpOptions,HttpPost,RouteHandler};
|
||||
use Syokuhou\IConfig;
|
||||
|
||||
final class SharpChatRoutes extends RouteHandler {
|
||||
private string $hashKey;
|
||||
|
@ -188,50 +188,7 @@ final class SharpChatRoutes extends RouteHandler {
|
|||
if(!hash_equals($realHash, $userHash))
|
||||
return ['success' => false, 'reason' => 'hash'];
|
||||
|
||||
if(strcasecmp($authMethod, 'Bearer') === 0) {
|
||||
$bearerCheck = $this->config->getString('bearerCheck');
|
||||
if($bearerCheck === '')
|
||||
return ['success' => false, 'reason' => 'unsupported'];
|
||||
|
||||
$req = curl_init($bearerCheck);
|
||||
try {
|
||||
curl_setopt_array($req, [
|
||||
CURLOPT_AUTOREFERER => false,
|
||||
CURLOPT_FAILONERROR => false,
|
||||
CURLOPT_FOLLOWLOCATION => false,
|
||||
CURLOPT_HEADER => false,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TCP_FASTOPEN => true,
|
||||
CURLOPT_CONNECTTIMEOUT => 2,
|
||||
CURLOPT_MAXREDIRS => 2,
|
||||
CURLOPT_PROTOCOLS => CURLPROTO_HTTPS,
|
||||
CURLOPT_TIMEOUT => 5,
|
||||
CURLOPT_USERAGENT => 'Misuzu',
|
||||
CURLOPT_HTTPHEADER => [
|
||||
sprintf('Authorization: Bearer %s', $authToken),
|
||||
],
|
||||
]);
|
||||
|
||||
$response = curl_exec($req);
|
||||
if($response === false)
|
||||
return ['success' => false, 'reason' => 'request'];
|
||||
} finally {
|
||||
curl_close($req);
|
||||
}
|
||||
|
||||
$decoded = json_decode($response);
|
||||
if($decoded === null)
|
||||
return ['success' => false, 'reason' => 'decode'];
|
||||
|
||||
if(empty($decoded->user_id))
|
||||
return ['success' => false, 'reason' => 'token'];
|
||||
|
||||
try {
|
||||
$userInfo = $this->usersCtx->getUsers()->getUser($decoded->user_id, 'id');
|
||||
} catch(RuntimeException $ex) {
|
||||
return ['success' => false, 'reason' => 'user'];
|
||||
}
|
||||
} elseif($authMethod === 'SESS' || strcasecmp($authMethod, 'Misuzu') === 0) {
|
||||
if($authMethod === 'SESS' || $authMethod === 'Misuzu') {
|
||||
$tokenPacker = $this->authCtx->createAuthTokenPacker();
|
||||
$tokenInfo = $tokenPacker->unpack($authToken);
|
||||
if($tokenInfo->isEmpty()) {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
namespace Misuzu;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Index\Base32;
|
||||
use Index\Serialisation\Base32;
|
||||
|
||||
class TOTPGenerator {
|
||||
public const DIGITS = 6;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu\Users;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
|
||||
class BanInfo {
|
||||
|
@ -69,8 +69,8 @@ class BanInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function isPermanent(): bool {
|
||||
|
@ -81,8 +81,8 @@ class BanInfo {
|
|||
return $this->expires;
|
||||
}
|
||||
|
||||
public function getExpiresAt(): ?CarbonImmutable {
|
||||
return $this->expires === null ? null : CarbonImmutable::createFromTimestampUTC($this->expires);
|
||||
public function getExpiresAt(): ?DateTime {
|
||||
return $this->expires === null ? null : DateTime::fromUnixTimeSeconds($this->expires);
|
||||
}
|
||||
|
||||
public function isActive(): bool {
|
||||
|
|
|
@ -3,11 +3,11 @@ namespace Misuzu\Users;
|
|||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use DateTimeInterface;
|
||||
use Misuzu\Pagination;
|
||||
use Index\DateTime;
|
||||
use Index\Data\DbStatementCache;
|
||||
use Index\Data\DbTools;
|
||||
use Index\Data\IDbConnection;
|
||||
use Misuzu\Pagination;
|
||||
|
||||
class Bans {
|
||||
public const SEVERITY_MAX = 10;
|
||||
|
@ -152,7 +152,7 @@ class Bans {
|
|||
|
||||
public function createBan(
|
||||
UserInfo|string $userInfo,
|
||||
DateTimeInterface|int|null $expires,
|
||||
DateTime|int|null $expires,
|
||||
string $publicReason,
|
||||
string $privateReason,
|
||||
int $severity = self::SEVERITY_DEFAULT,
|
||||
|
@ -164,8 +164,8 @@ class Bans {
|
|||
$userInfo = $userInfo->getId();
|
||||
if($modInfo instanceof UserInfo)
|
||||
$modInfo = $modInfo->getId();
|
||||
if($expires instanceof DateTimeInterface)
|
||||
$expires = (int)$expires->format('U');
|
||||
if($expires instanceof DateTime)
|
||||
$expires = $expires->getUnixTimeSeconds();
|
||||
|
||||
$stmt = $this->cache->get('INSERT INTO msz_users_bans (user_id, mod_id, ban_severity, ban_reason_public, ban_reason_private, ban_expires) VALUES (?, ?, ?, ?, ?, FROM_UNIXTIME(?))');
|
||||
$stmt->addParameter(1, $userInfo);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu\Users;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
|
||||
class ModNoteInfo {
|
||||
|
@ -45,8 +45,8 @@ class ModNoteInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function getTitle(): string {
|
||||
|
|
|
@ -2,14 +2,13 @@
|
|||
namespace Misuzu\Users;
|
||||
|
||||
use Stringable;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Colour\Colour;
|
||||
use Index\Data\IDbResult;
|
||||
|
||||
class RoleInfo implements Stringable {
|
||||
public function __construct(
|
||||
private string $id,
|
||||
private ?string $string,
|
||||
private int $rank,
|
||||
private string $name,
|
||||
private ?string $title,
|
||||
|
@ -23,15 +22,14 @@ class RoleInfo implements Stringable {
|
|||
public static function fromResult(IDbResult $result): RoleInfo {
|
||||
return new RoleInfo(
|
||||
id: $result->getString(0),
|
||||
string: $result->getStringOrNull(1),
|
||||
rank: $result->getInteger(2),
|
||||
name: $result->getString(3),
|
||||
title: $result->getStringOrNull(4),
|
||||
description: $result->getStringOrNull(5),
|
||||
hidden: $result->getBoolean(6),
|
||||
leavable: $result->getBoolean(7),
|
||||
colour: $result->getIntegerOrNull(8),
|
||||
created: $result->getInteger(9),
|
||||
rank: $result->getInteger(1),
|
||||
name: $result->getString(2),
|
||||
title: $result->getStringOrNull(3),
|
||||
description: $result->getStringOrNull(4),
|
||||
hidden: $result->getBoolean(5),
|
||||
leavable: $result->getBoolean(6),
|
||||
colour: $result->getIntegerOrNull(7),
|
||||
created: $result->getInteger(8),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -43,14 +41,6 @@ class RoleInfo implements Stringable {
|
|||
return $this->id === Roles::DEFAULT_ROLE;
|
||||
}
|
||||
|
||||
public function hasString(): bool {
|
||||
return $this->string !== null && $this->string !== '';
|
||||
}
|
||||
|
||||
public function getString(): ?string {
|
||||
return $this->string;
|
||||
}
|
||||
|
||||
public function getRank(): int {
|
||||
return $this->rank;
|
||||
}
|
||||
|
@ -99,8 +89,8 @@ class RoleInfo implements Stringable {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function __toString(): string {
|
||||
|
|
|
@ -57,8 +57,6 @@ class Roles {
|
|||
public function getRoles(
|
||||
UserInfo|string|null $userInfo = null,
|
||||
?bool $hidden = null,
|
||||
?bool $hasString = null,
|
||||
bool $orderByRank = false,
|
||||
?Pagination $pagination = null
|
||||
): iterable {
|
||||
if($userInfo instanceof UserInfo)
|
||||
|
@ -69,26 +67,23 @@ class Roles {
|
|||
$hasPagination = $pagination !== null;
|
||||
|
||||
$args = 0;
|
||||
$query = 'SELECT role_id, role_string, role_hierarchy, role_name, role_title, role_description, role_hidden, role_can_leave, role_colour, UNIX_TIMESTAMP(role_created) FROM msz_roles';
|
||||
$query = 'SELECT role_id, role_hierarchy, role_name, role_title, role_description, role_hidden, role_can_leave, role_colour, UNIX_TIMESTAMP(role_created) FROM msz_roles';
|
||||
if($hasUserInfo) {
|
||||
++$args;
|
||||
$query .= ' WHERE role_id IN (SELECT role_id FROM msz_users_roles WHERE user_id = ?)';
|
||||
}
|
||||
if($hasHidden)
|
||||
$query .= sprintf(' %s role_hidden %s 0', ++$args > 1 ? 'AND' : 'WHERE', $hidden ? '<>' : '=');
|
||||
if($hasString)
|
||||
$query .= sprintf(' %s role_string %s NULL', ++$args > 1 ? 'AND' : 'WHERE', $hasString ? 'IS NOT' : 'IS');
|
||||
if($orderByRank)
|
||||
$query .= ' ORDER BY role_hierarchy DESC';
|
||||
if($hasPagination)
|
||||
$query .= ' LIMIT ? OFFSET ?';
|
||||
|
||||
$args = 0;
|
||||
$stmt = $this->cache->get($query);
|
||||
if($hasUserInfo)
|
||||
$stmt->nextParameter($userInfo);
|
||||
$stmt->addParameter(++$args, $userInfo);
|
||||
if($hasPagination) {
|
||||
$stmt->nextParameter($pagination->getRange());
|
||||
$stmt->nextParameter($pagination->getOffset());
|
||||
$stmt->addParameter(++$args, $pagination->getRange());
|
||||
$stmt->addParameter(++$args, $pagination->getOffset());
|
||||
}
|
||||
$stmt->execute();
|
||||
|
||||
|
@ -96,7 +91,7 @@ class Roles {
|
|||
}
|
||||
|
||||
public function getRole(string $roleId): RoleInfo {
|
||||
$stmt = $this->cache->get('SELECT role_id, role_string, role_hierarchy, role_name, role_title, role_description, role_hidden, role_can_leave, role_colour, UNIX_TIMESTAMP(role_created) FROM msz_roles WHERE role_id = ?');
|
||||
$stmt = $this->cache->get('SELECT role_id, role_hierarchy, role_name, role_title, role_description, role_hidden, role_can_leave, role_colour, UNIX_TIMESTAMP(role_created) FROM msz_roles WHERE role_id = ?');
|
||||
$stmt->addParameter(1, $roleId);
|
||||
$stmt->execute();
|
||||
|
||||
|
@ -111,7 +106,6 @@ class Roles {
|
|||
string $name,
|
||||
int $rank,
|
||||
Colour $colour,
|
||||
string $string = '',
|
||||
string $title = '',
|
||||
string $description = '',
|
||||
bool $hidden = false,
|
||||
|
@ -119,22 +113,18 @@ class Roles {
|
|||
): RoleInfo {
|
||||
$colour = $colour->shouldInherit() ? null : Colour::toMisuzu($colour);
|
||||
|
||||
if($string === '')
|
||||
$string = null;
|
||||
|
||||
// should these continue to accept NULL?
|
||||
if($title === '') $title = null;
|
||||
if($description === '') $description = null;
|
||||
|
||||
$stmt = $this->cache->get('INSERT INTO msz_roles (role_string, role_hierarchy, role_name, role_title, role_description, role_hidden, role_can_leave, role_colour) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
|
||||
$stmt->nextParameter($string);
|
||||
$stmt->nextParameter($rank);
|
||||
$stmt->nextParameter($name);
|
||||
$stmt->nextParameter($title);
|
||||
$stmt->nextParameter($description);
|
||||
$stmt->nextParameter($hidden ? 1 : 0);
|
||||
$stmt->nextParameter($leavable ? 1 : 0);
|
||||
$stmt->nextParameter($colour);
|
||||
$stmt = $this->cache->get('INSERT INTO msz_roles (role_hierarchy, role_name, role_title, role_description, role_hidden, role_can_leave, role_colour) VALUES (?, ?, ?, ?, ?, ?, ?)');
|
||||
$stmt->addParameter(1, $rank);
|
||||
$stmt->addParameter(2, $name);
|
||||
$stmt->addParameter(3, $title);
|
||||
$stmt->addParameter(4, $description);
|
||||
$stmt->addParameter(5, $hidden ? 1 : 0);
|
||||
$stmt->addParameter(6, $leavable ? 1 : 0);
|
||||
$stmt->addParameter(7, $colour);
|
||||
$stmt->execute();
|
||||
|
||||
return $this->getRole((string)$this->dbConn->getLastInsertId());
|
||||
|
@ -166,7 +156,6 @@ class Roles {
|
|||
|
||||
public function updateRole(
|
||||
RoleInfo|string $roleInfo,
|
||||
?string $string = null,
|
||||
?string $name = null,
|
||||
?int $rank = null,
|
||||
?Colour $colour = null,
|
||||
|
@ -178,7 +167,6 @@ class Roles {
|
|||
if($roleInfo instanceof RoleInfo)
|
||||
$roleInfo = $roleInfo->getId();
|
||||
|
||||
$applyString = $string !== null;
|
||||
$applyTitle = $title !== null;
|
||||
$applyDescription = $description !== null;
|
||||
$applyColour = $colour !== null;
|
||||
|
@ -188,29 +176,24 @@ class Roles {
|
|||
if($applyColour)
|
||||
$colour = $colour->shouldInherit() ? null : Colour::toMisuzu($colour);
|
||||
|
||||
if($string === '')
|
||||
$string = null;
|
||||
|
||||
// should these continue to accept NULL?
|
||||
if($title === '') $title = null;
|
||||
if($description === '') $description = null;
|
||||
|
||||
$stmt = $this->cache->get('UPDATE msz_roles SET role_string = IF(?, ?, role_string), role_hierarchy = COALESCE(?, role_hierarchy), role_name = COALESCE(?, role_name), role_title = IF(?, ?, role_title), role_description = IF(?, ?, role_description), role_hidden = IF(?, ?, role_hidden), role_can_leave = IF(?, ?, role_can_leave), role_colour = IF(?, ?, role_colour) WHERE role_id = ?');
|
||||
$stmt->nextParameter($applyString ? 1 : 0);
|
||||
$stmt->nextParameter($string);
|
||||
$stmt->nextParameter($rank);
|
||||
$stmt->nextParameter($name);
|
||||
$stmt->nextParameter($applyTitle ? 1 : 0);
|
||||
$stmt->nextParameter($title);
|
||||
$stmt->nextParameter($applyDescription ? 1 : 0);
|
||||
$stmt->nextParameter($description);
|
||||
$stmt->nextParameter($applyHidden ? 1 : 0);
|
||||
$stmt->nextParameter($hidden ? 1 : 0);
|
||||
$stmt->nextParameter($applyLeavable ? 1 : 0);
|
||||
$stmt->nextParameter($leavable ? 1 : 0);
|
||||
$stmt->nextParameter($applyColour ? 1 : 0);
|
||||
$stmt->nextParameter($colour);
|
||||
$stmt->nextParameter($roleInfo);
|
||||
$stmt = $this->cache->get('UPDATE msz_roles SET role_hierarchy = COALESCE(?, role_hierarchy), role_name = COALESCE(?, role_name), role_title = IF(?, ?, role_title), role_description = IF(?, ?, role_description), role_hidden = IF(?, ?, role_hidden), role_can_leave = IF(?, ?, role_can_leave), role_colour = IF(?, ?, role_colour) WHERE role_id = ?');
|
||||
$stmt->addParameter(1, $rank);
|
||||
$stmt->addParameter(2, $name);
|
||||
$stmt->addParameter(3, $applyTitle ? 1 : 0);
|
||||
$stmt->addParameter(4, $title);
|
||||
$stmt->addParameter(5, $applyDescription ? 1 : 0);
|
||||
$stmt->addParameter(6, $description);
|
||||
$stmt->addParameter(7, $applyHidden ? 1 : 0);
|
||||
$stmt->addParameter(8, $hidden ? 1 : 0);
|
||||
$stmt->addParameter(9, $applyLeavable ? 1 : 0);
|
||||
$stmt->addParameter(10, $leavable ? 1 : 0);
|
||||
$stmt->addParameter(11, $applyColour ? 1 : 0);
|
||||
$stmt->addParameter(12, $colour);
|
||||
$stmt->addParameter(13, $roleInfo);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
<?php
|
||||
namespace Misuzu\Users;
|
||||
|
||||
use Misuzu\Parsers\Parser;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\TimeZoneInfo;
|
||||
use Index\Colour\Colour;
|
||||
use Index\Data\IDbResult;
|
||||
use Index\Net\IPAddress;
|
||||
use Misuzu\Parsers\Parser;
|
||||
|
||||
class UserInfo {
|
||||
public function __construct(
|
||||
|
@ -130,8 +131,8 @@ class UserInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
|
||||
public function hasLastActive(): bool {
|
||||
|
@ -142,8 +143,8 @@ class UserInfo {
|
|||
return $this->lastActive;
|
||||
}
|
||||
|
||||
public function getLastActiveAt(): ?CarbonImmutable {
|
||||
return $this->lastActive === null ? null : CarbonImmutable::createFromTimestampUTC($this->lastActive);
|
||||
public function getLastActiveAt(): ?DateTime {
|
||||
return $this->lastActive === null ? null : DateTime::fromUnixTimeSeconds($this->lastActive);
|
||||
}
|
||||
|
||||
public function isDeleted(): bool {
|
||||
|
@ -154,8 +155,8 @@ class UserInfo {
|
|||
return $this->deleted;
|
||||
}
|
||||
|
||||
public function getDeletedAt(): ?CarbonImmutable {
|
||||
return $this->deleted === null ? null : CarbonImmutable::createFromTimestampUTC($this->deleted);
|
||||
public function getDeletedAt(): ?DateTime {
|
||||
return $this->deleted === null ? null : DateTime::fromUnixTimeSeconds($this->deleted);
|
||||
}
|
||||
|
||||
public function hasDisplayRoleId(): bool {
|
||||
|
@ -230,15 +231,15 @@ class UserInfo {
|
|||
return $this->birthdate;
|
||||
}
|
||||
|
||||
public function getBirthdate(): ?CarbonImmutable {
|
||||
return $this->birthdate === null ? null : CarbonImmutable::createFromFormat('Y-m-d', $this->birthdate, 'UTC');
|
||||
public function getBirthdate(): ?DateTime {
|
||||
return $this->birthdate === null ? null : DateTime::createFromFormat('Y-m-d', $this->birthdate, TimeZoneInfo::utc());
|
||||
}
|
||||
|
||||
public function getAge(): int {
|
||||
$birthdate = $this->getBirthdate();
|
||||
if($birthdate === null || (int)$birthdate->format('Y') < 1900)
|
||||
if($birthdate === null || $birthdate->getYear() < 1900)
|
||||
return -1;
|
||||
return (int)$birthdate->diff(CarbonImmutable::now())->format('%y');
|
||||
return (int)$birthdate->diff(DateTime::now())->format('%y');
|
||||
}
|
||||
|
||||
public function hasBackgroundSettings(): bool {
|
||||
|
|
|
@ -3,7 +3,7 @@ namespace Misuzu\Users;
|
|||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use DateTimeInterface;
|
||||
use Index\DateTime;
|
||||
use Index\XString;
|
||||
use Index\Colour\Colour;
|
||||
use Index\Data\DbStatementCache;
|
||||
|
@ -46,7 +46,7 @@ class Users {
|
|||
UserInfo|string|null $after = null,
|
||||
?int $lastActiveInMinutes = null,
|
||||
?int $newerThanDays = null,
|
||||
?DateTimeInterface $birthdate = null,
|
||||
?DateTime $birthdate = null,
|
||||
?bool $deleted = null
|
||||
): int {
|
||||
if($roleInfo instanceof RoleInfo)
|
||||
|
@ -106,7 +106,7 @@ class Users {
|
|||
UserInfo|string|null $after = null,
|
||||
?int $lastActiveInMinutes = null,
|
||||
?int $newerThanDays = null,
|
||||
?DateTimeInterface $birthdate = null,
|
||||
?DateTime $birthdate = null,
|
||||
?bool $deleted = null,
|
||||
?string $orderBy = null,
|
||||
?bool $reverseOrder = null,
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
<?php
|
||||
namespace Misuzu\Users;
|
||||
|
||||
use RuntimeException;
|
||||
use Misuzu\SiteInfo;
|
||||
use Misuzu\URLs\URLRegistry;
|
||||
use Misuzu\Users\Assets\UserAvatarAsset;
|
||||
use Aiwass\Server\{RpcActionHandler,RpcQuery};
|
||||
use Index\XArray;
|
||||
use Index\Colour\{Colour,ColourRGB};
|
||||
|
||||
final class UsersRpcActions extends RpcActionHandler {
|
||||
public function __construct(
|
||||
private SiteInfo $siteInfo,
|
||||
private URLRegistry $urls,
|
||||
private UsersContext $usersCtx
|
||||
) {}
|
||||
|
||||
#[RpcQuery('misuzu:users:getUser')]
|
||||
public function queryGetUser(string $userId): array {
|
||||
try {
|
||||
$userInfo = $this->usersCtx->getUserInfo($userId, Users::GET_USER_ID);
|
||||
} catch(RuntimeException) {
|
||||
return ['error' => 'notfound'];
|
||||
}
|
||||
|
||||
// TODO: there should be some kinda privacy controls for users
|
||||
|
||||
$rank = $this->usersCtx->getUserRank($userInfo);
|
||||
|
||||
$colour = $this->usersCtx->getUserColour($userInfo);
|
||||
if($colour->shouldInherit()) {
|
||||
$colourRaw = null;
|
||||
$colourCSS = (string)$colour;
|
||||
} else {
|
||||
// Index doesn't have a proper toRawRGB func???
|
||||
$colourRaw = Colour::toMisuzu($colour) & 0xFFFFFF;
|
||||
$colourCSS = (string)ColourRGB::convert($colour);
|
||||
}
|
||||
|
||||
$baseUrl = $this->siteInfo->getURL();
|
||||
|
||||
$avatars = [];
|
||||
$formatAvatarUrl = fn($res = 0) => (
|
||||
$baseUrl . $this->urls->format('user-avatar', ['user' => $userInfo->getId(), 'res' => $res])
|
||||
);
|
||||
|
||||
$avatars[] = ['res' => 0, 'url' => $formatAvatarUrl()];
|
||||
foreach(UserAvatarAsset::DIMENSIONS as $res)
|
||||
$avatars[] = ['res' => $res, 'url' => $formatAvatarUrl($res)];
|
||||
|
||||
$avatars = array_reverse($avatars);
|
||||
|
||||
$output = [
|
||||
'id' => $userInfo->getId(),
|
||||
'name' => $userInfo->getName(),
|
||||
'colour_raw' => $colourRaw,
|
||||
'colour_css' => $colourCSS,
|
||||
'rank' => $rank,
|
||||
'country_code' => $userInfo->getCountryCode(),
|
||||
'avatar_urls' => $avatars,
|
||||
'profile_url' => $baseUrl . $this->urls->format('user-profile', ['user' => $userInfo->getId()]),
|
||||
'created_at' => $userInfo->getCreatedAt()->toIso8601ZuluString(),
|
||||
];
|
||||
|
||||
if($userInfo->hasLastActive())
|
||||
$output['last_active_at'] = $userInfo->getLastActiveAt()->toIso8601ZuluString();
|
||||
|
||||
$roles = XArray::select(
|
||||
$this->usersCtx->getRoles()->getRoles(userInfo: $userInfo, hasString: true, orderByRank: true),
|
||||
fn($roleInfo) => $roleInfo->getString(),
|
||||
);
|
||||
if(!empty($roles))
|
||||
$output['roles'] = $roles;
|
||||
|
||||
if($userInfo->hasTitle())
|
||||
$output['title'] = $userInfo->getTitle();
|
||||
|
||||
if($userInfo->isSuperUser())
|
||||
$output['is_super'] = true;
|
||||
if($userInfo->isDeleted())
|
||||
$output['is_deleted'] = true;
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu\Users;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
use Index\DateTime;
|
||||
use Index\Data\IDbResult;
|
||||
|
||||
class WarningInfo {
|
||||
|
@ -55,7 +55,7 @@ class WarningInfo {
|
|||
return $this->created;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): CarbonImmutable {
|
||||
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||
public function getCreatedAt(): DateTime {
|
||||
return DateTime::fromUnixTimeSeconds($this->created);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,13 +17,6 @@
|
|||
</div>
|
||||
</label>
|
||||
|
||||
<label class="form__label">
|
||||
<div class="form__label__text">Role String (used in API)</div>
|
||||
<div class="form__label__input">
|
||||
{{ input_text('ur_string', '', role_ur_string|default(role_info.string|default()), 'text', '', false, {'maxlength':20}) }}
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label class="form__label">
|
||||
<div class="form__label__text">Hide Role</div>
|
||||
<div class="form__label__input">
|
||||
|
@ -51,6 +44,7 @@
|
|||
{{ input_text('ur_title', '', role_ur_title|default(role_info.title|default()), 'text', '', false, {'maxlength':64}) }}
|
||||
</div>
|
||||
</label>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
|
|
Loading…
Reference in a new issue