Compare commits
7 commits
Author | SHA1 | Date | |
---|---|---|---|
f547812d5a | |||
8a06836985 | |||
34528ae413 | |||
0bf7ca0d52 | |||
cc9fccdf18 | |||
ca77b501e7 | |||
2439f87df9 |
51 changed files with 1084 additions and 367 deletions
|
@ -1,15 +1,15 @@
|
||||||
{
|
{
|
||||||
"minimum-stability": "dev",
|
|
||||||
"prefer-stable": true,
|
|
||||||
"require": {
|
"require": {
|
||||||
"flashwave/index": "dev-master",
|
"flashwave/index": "^0.2408.40014",
|
||||||
"flashwave/sasae": "dev-master",
|
"flashwave/sasae": "^1.1",
|
||||||
|
"flashwave/syokuhou": "^1.2",
|
||||||
"erusev/parsedown": "~1.6",
|
"erusev/parsedown": "~1.6",
|
||||||
"chillerlan/php-qrcode": "^4.3",
|
"chillerlan/php-qrcode": "^4.3",
|
||||||
"symfony/mailer": "^6.0",
|
"symfony/mailer": "^6.0",
|
||||||
"matomo/device-detector": "^6.1",
|
"matomo/device-detector": "^6.1",
|
||||||
"sentry/sdk": "^4.0",
|
"sentry/sdk": "^4.0",
|
||||||
"flashwave/syokuhou": "dev-master"
|
"nesbot/carbon": "^3.7",
|
||||||
|
"flashwave/aiwass": "^1.0"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": [
|
"classmap": [
|
||||||
|
@ -34,6 +34,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "^1.10"
|
"phpstan/phpstan": "^1.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
672
composer.lock
generated
672
composer.lock
generated
|
@ -4,8 +4,77 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "a21e81f36e0bcc863143a9d85b28c8ff",
|
"content-hash": "c8edfa21e13dedc126a6351b7d367559",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "carbonphp/carbon-doctrine-types",
|
||||||
|
"version": "3.2.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/CarbonPHP/carbon-doctrine-types.git",
|
||||||
|
"reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/18ba5ddfec8976260ead6e866180bd5d2f71aa1d",
|
||||||
|
"reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^8.1"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"doctrine/dbal": "<4.0.0 || >=5.0.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/dbal": "^4.0.0",
|
||||||
|
"nesbot/carbon": "^2.71.0 || ^3.0.0",
|
||||||
|
"phpunit/phpunit": "^10.3"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Carbon\\Doctrine\\": "src/Carbon/Doctrine/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "KyleKatarn",
|
||||||
|
"email": "kylekatarnls@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Types to use Carbon in Doctrine",
|
||||||
|
"keywords": [
|
||||||
|
"carbon",
|
||||||
|
"date",
|
||||||
|
"datetime",
|
||||||
|
"doctrine",
|
||||||
|
"time"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues",
|
||||||
|
"source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/kylekatarnls",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://opencollective.com/Carbon",
|
||||||
|
"type": "open_collective"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/nesbot/carbon",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-02-09T16:56:22+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "chillerlan/php-qrcode",
|
"name": "chillerlan/php-qrcode",
|
||||||
"version": "4.4.1",
|
"version": "4.4.1",
|
||||||
|
@ -347,32 +416,67 @@
|
||||||
},
|
},
|
||||||
"time": "2019-12-30T22:54:17+00:00"
|
"time": "2019-12-30T22:54:17+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "flashwave/aiwass",
|
||||||
|
"version": "v1.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://patchii.net/flashii/aiwass.git",
|
||||||
|
"reference": "de27da54b603f0fdc06dab89341908e73ea7a880"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-msgpack": ">=2.2",
|
||||||
|
"flashwave/index": "^0.2408.40014",
|
||||||
|
"php": ">=8.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "^1.11",
|
||||||
|
"phpunit/phpunit": "^11.2"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Aiwass\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"bsd-3-clause-clear"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "flashwave",
|
||||||
|
"email": "packagist@flash.moe",
|
||||||
|
"homepage": "https://flash.moe",
|
||||||
|
"role": "mom"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Shared HTTP RPC client/server library.",
|
||||||
|
"homepage": "https://railgun.sh/aiwass",
|
||||||
|
"time": "2024-08-16T15:59:19+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "flashwave/index",
|
"name": "flashwave/index",
|
||||||
"version": "dev-master",
|
"version": "v0.2408.40014",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://patchii.net/flash/index.git",
|
"url": "https://patchii.net/flash/index.git",
|
||||||
"reference": "e4c8ed711e045cffe840ba10a239ede14b0b171f"
|
"reference": "fbca708fbd75e8ecc6b36b39c1307a67bf250808"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"php": ">=8.1"
|
"php": ">=8.3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "^1.10",
|
"phpstan/phpstan": "^1.11",
|
||||||
"phpunit/phpunit": "^10.2"
|
"phpunit/phpunit": "^11.2"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-mysqli": "Support for the Index\\Data\\MariaDB namespace (both mysqlnd and libmysql are supported).",
|
"ext-mysqli": "Support for the Index\\Data\\MariaDB namespace (both mysqlnd and libmysql are supported).",
|
||||||
"ext-sqlite3": "Support for the Index\\Data\\SQLite namespace."
|
"ext-sqlite3": "Support for the Index\\Data\\SQLite namespace."
|
||||||
},
|
},
|
||||||
"default-branch": true,
|
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"files": [
|
|
||||||
"index.php"
|
|
||||||
],
|
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Index\\": "src"
|
"Index\\": "src"
|
||||||
}
|
}
|
||||||
|
@ -391,27 +495,26 @@
|
||||||
],
|
],
|
||||||
"description": "Composer package for the common library for my projects.",
|
"description": "Composer package for the common library for my projects.",
|
||||||
"homepage": "https://railgun.sh/index",
|
"homepage": "https://railgun.sh/index",
|
||||||
"time": "2024-04-10T23:40:14+00:00"
|
"time": "2024-08-04T00:14:17+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "flashwave/sasae",
|
"name": "flashwave/sasae",
|
||||||
"version": "dev-master",
|
"version": "v1.1.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://patchii.net/flash/sasae.git",
|
"url": "https://patchii.net/flash/sasae.git",
|
||||||
"reference": "c8a9f2974e6591215b3f898dd5525de1e8367f66"
|
"reference": "ad63107a4387aa35c45bce71c2d6262a15b96f9d"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"flashwave/index": "dev-master",
|
"flashwave/index": "^0.2408.40014",
|
||||||
"php": ">=8.2",
|
"php": ">=8.3",
|
||||||
"twig/html-extra": "^3.7",
|
"twig/html-extra": "^3.10",
|
||||||
"twig/twig": "^3.7"
|
"twig/twig": "^3.10"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "^1.10",
|
"phpstan/phpstan": "^1.11",
|
||||||
"phpunit/phpunit": "^10.2"
|
"phpunit/phpunit": "^11.2"
|
||||||
},
|
},
|
||||||
"default-branch": true,
|
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
@ -432,25 +535,24 @@
|
||||||
],
|
],
|
||||||
"description": "A wrapper for Twig with added common functionality.",
|
"description": "A wrapper for Twig with added common functionality.",
|
||||||
"homepage": "https://railgun.sh/sasae",
|
"homepage": "https://railgun.sh/sasae",
|
||||||
"time": "2024-01-04T02:13:42+00:00"
|
"time": "2024-08-04T00:48:17+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "flashwave/syokuhou",
|
"name": "flashwave/syokuhou",
|
||||||
"version": "dev-master",
|
"version": "v1.2.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://patchii.net/flash/syokuhou.git",
|
"url": "https://patchii.net/flash/syokuhou.git",
|
||||||
"reference": "954a07b95110a43e64dd6e20b2a25f4676c71a08"
|
"reference": "129a46c0d917382f9bc195cce278be51984eb87d"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"flashwave/index": "dev-master",
|
"flashwave/index": "^0.2408.40014",
|
||||||
"php": ">=8.2"
|
"php": ">=8.3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "^1.10",
|
"phpstan/phpstan": "^1.11",
|
||||||
"phpunit/phpunit": "^10.4"
|
"phpunit/phpunit": "^11.2"
|
||||||
},
|
},
|
||||||
"default-branch": true,
|
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
@ -471,20 +573,20 @@
|
||||||
],
|
],
|
||||||
"description": "Configuration library for PHP.",
|
"description": "Configuration library for PHP.",
|
||||||
"homepage": "https://railgun.sh/syokuhou",
|
"homepage": "https://railgun.sh/syokuhou",
|
||||||
"time": "2024-06-03T22:59:30+00:00"
|
"time": "2024-08-04T01:07:23+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/psr7",
|
"name": "guzzlehttp/psr7",
|
||||||
"version": "2.6.2",
|
"version": "2.7.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/guzzle/psr7.git",
|
"url": "https://github.com/guzzle/psr7.git",
|
||||||
"reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221"
|
"reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221",
|
"url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
|
||||||
"reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221",
|
"reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -499,8 +601,8 @@
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||||
"http-interop/http-factory-tests": "^0.9",
|
"http-interop/http-factory-tests": "0.9.0",
|
||||||
"phpunit/phpunit": "^8.5.36 || ^9.6.15"
|
"phpunit/phpunit": "^8.5.39 || ^9.6.20"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
|
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
|
||||||
|
@ -571,7 +673,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/guzzle/psr7/issues",
|
"issues": "https://github.com/guzzle/psr7/issues",
|
||||||
"source": "https://github.com/guzzle/psr7/tree/2.6.2"
|
"source": "https://github.com/guzzle/psr7/tree/2.7.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
@ -587,7 +689,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-12-03T20:05:35+00:00"
|
"time": "2024-07-18T11:15:46+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "jean85/pretty-package-versions",
|
"name": "jean85/pretty-package-versions",
|
||||||
|
@ -771,6 +873,160 @@
|
||||||
},
|
},
|
||||||
"time": "2019-09-10T13:16:29+00:00"
|
"time": "2019-09-10T13:16:29+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "nesbot/carbon",
|
||||||
|
"version": "3.7.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/briannesbitt/Carbon.git",
|
||||||
|
"reference": "cb4374784c87d0a0294e8513a52eb63c0aff3139"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/cb4374784c87d0a0294e8513a52eb63c0aff3139",
|
||||||
|
"reference": "cb4374784c87d0a0294e8513a52eb63c0aff3139",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"carbonphp/carbon-doctrine-types": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"php": "^8.1",
|
||||||
|
"psr/clock": "^1.0",
|
||||||
|
"symfony/clock": "^6.3 || ^7.0",
|
||||||
|
"symfony/polyfill-mbstring": "^1.0",
|
||||||
|
"symfony/translation": "^4.4.18 || ^5.2.1|| ^6.0 || ^7.0"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"psr/clock-implementation": "1.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/dbal": "^3.6.3 || ^4.0",
|
||||||
|
"doctrine/orm": "^2.15.2 || ^3.0",
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.57.2",
|
||||||
|
"kylekatarnls/multi-tester": "^2.5.3",
|
||||||
|
"ondrejmirtes/better-reflection": "^6.25.0.4",
|
||||||
|
"phpmd/phpmd": "^2.15.0",
|
||||||
|
"phpstan/extension-installer": "^1.3.1",
|
||||||
|
"phpstan/phpstan": "^1.11.2",
|
||||||
|
"phpunit/phpunit": "^10.5.20",
|
||||||
|
"squizlabs/php_codesniffer": "^3.9.0"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/carbon"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.x-dev",
|
||||||
|
"dev-2.x": "2.x-dev"
|
||||||
|
},
|
||||||
|
"laravel": {
|
||||||
|
"providers": [
|
||||||
|
"Carbon\\Laravel\\ServiceProvider"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"phpstan": {
|
||||||
|
"includes": [
|
||||||
|
"extension.neon"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Carbon\\": "src/Carbon/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Brian Nesbitt",
|
||||||
|
"email": "brian@nesbot.com",
|
||||||
|
"homepage": "https://markido.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "kylekatarnls",
|
||||||
|
"homepage": "https://github.com/kylekatarnls"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "An API extension for DateTime that supports 281 different languages.",
|
||||||
|
"homepage": "https://carbon.nesbot.com",
|
||||||
|
"keywords": [
|
||||||
|
"date",
|
||||||
|
"datetime",
|
||||||
|
"time"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"docs": "https://carbon.nesbot.com/docs",
|
||||||
|
"issues": "https://github.com/briannesbitt/Carbon/issues",
|
||||||
|
"source": "https://github.com/briannesbitt/Carbon"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/sponsors/kylekatarnls",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://opencollective.com/Carbon#sponsor",
|
||||||
|
"type": "opencollective"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-07-16T22:29:20+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "psr/clock",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-fig/clock.git",
|
||||||
|
"reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d",
|
||||||
|
"reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.0 || ^8.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Psr\\Clock\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "PHP-FIG",
|
||||||
|
"homepage": "https://www.php-fig.org/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Common interface for reading the clock.",
|
||||||
|
"homepage": "https://github.com/php-fig/clock",
|
||||||
|
"keywords": [
|
||||||
|
"clock",
|
||||||
|
"now",
|
||||||
|
"psr",
|
||||||
|
"psr-20",
|
||||||
|
"time"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/php-fig/clock/issues",
|
||||||
|
"source": "https://github.com/php-fig/clock/tree/1.0.0"
|
||||||
|
},
|
||||||
|
"time": "2022-11-25T14:36:26+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/container",
|
"name": "psr/container",
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
|
@ -1220,6 +1476,80 @@
|
||||||
],
|
],
|
||||||
"time": "2024-07-16T13:45:27+00:00"
|
"time": "2024-07-16T13:45:27+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/clock",
|
||||||
|
"version": "v7.1.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/clock.git",
|
||||||
|
"reference": "3dfc8b084853586de51dd1441c6242c76a28cbe7"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/clock/zipball/3dfc8b084853586de51dd1441c6242c76a28cbe7",
|
||||||
|
"reference": "3dfc8b084853586de51dd1441c6242c76a28cbe7",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.2",
|
||||||
|
"psr/clock": "^1.0",
|
||||||
|
"symfony/polyfill-php83": "^1.28"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"psr/clock-implementation": "1.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"Resources/now.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Clock\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Decouples applications from the system clock",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"clock",
|
||||||
|
"psr20",
|
||||||
|
"time"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/clock/tree/v7.1.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-05-31T14:57:53+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/deprecation-contracts",
|
"name": "symfony/deprecation-contracts",
|
||||||
"version": "v3.5.0",
|
"version": "v3.5.0",
|
||||||
|
@ -2151,6 +2481,82 @@
|
||||||
],
|
],
|
||||||
"time": "2024-05-31T15:07:36+00:00"
|
"time": "2024-05-31T15:07:36+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-php83",
|
||||||
|
"version": "v1.30.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-php83.git",
|
||||||
|
"reference": "dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9",
|
||||||
|
"reference": "dbdcdf1a4dcc2743591f1079d0c35ab1e2dcbbc9",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.1"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"name": "symfony/polyfill",
|
||||||
|
"url": "https://github.com/symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Php83\\": ""
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"Resources/stubs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-php83/tree/v1.30.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-06-19T12:35:24+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/service-contracts",
|
"name": "symfony/service-contracts",
|
||||||
"version": "v3.5.0",
|
"version": "v3.5.0",
|
||||||
|
@ -2234,6 +2640,178 @@
|
||||||
],
|
],
|
||||||
"time": "2024-04-18T09:32:20+00:00"
|
"time": "2024-04-18T09:32:20+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/translation",
|
||||||
|
"version": "v7.1.3",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/translation.git",
|
||||||
|
"reference": "8d5e50c813ba2859a6dfc99a0765c550507934a1"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/translation/zipball/8d5e50c813ba2859a6dfc99a0765c550507934a1",
|
||||||
|
"reference": "8d5e50c813ba2859a6dfc99a0765c550507934a1",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.2",
|
||||||
|
"symfony/polyfill-mbstring": "~1.0",
|
||||||
|
"symfony/translation-contracts": "^2.5|^3.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"symfony/config": "<6.4",
|
||||||
|
"symfony/console": "<6.4",
|
||||||
|
"symfony/dependency-injection": "<6.4",
|
||||||
|
"symfony/http-client-contracts": "<2.5",
|
||||||
|
"symfony/http-kernel": "<6.4",
|
||||||
|
"symfony/service-contracts": "<2.5",
|
||||||
|
"symfony/twig-bundle": "<6.4",
|
||||||
|
"symfony/yaml": "<6.4"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"symfony/translation-implementation": "2.3|3.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"nikic/php-parser": "^4.18|^5.0",
|
||||||
|
"psr/log": "^1|^2|^3",
|
||||||
|
"symfony/config": "^6.4|^7.0",
|
||||||
|
"symfony/console": "^6.4|^7.0",
|
||||||
|
"symfony/dependency-injection": "^6.4|^7.0",
|
||||||
|
"symfony/finder": "^6.4|^7.0",
|
||||||
|
"symfony/http-client-contracts": "^2.5|^3.0",
|
||||||
|
"symfony/http-kernel": "^6.4|^7.0",
|
||||||
|
"symfony/intl": "^6.4|^7.0",
|
||||||
|
"symfony/polyfill-intl-icu": "^1.21",
|
||||||
|
"symfony/routing": "^6.4|^7.0",
|
||||||
|
"symfony/service-contracts": "^2.5|^3",
|
||||||
|
"symfony/yaml": "^6.4|^7.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"Resources/functions.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Translation\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Tests/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Provides tools to internationalize your application",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/translation/tree/v7.1.3"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-07-26T12:41:01+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/translation-contracts",
|
||||||
|
"version": "v3.5.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/translation-contracts.git",
|
||||||
|
"reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a",
|
||||||
|
"reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.1"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.5-dev"
|
||||||
|
},
|
||||||
|
"thanks": {
|
||||||
|
"name": "symfony/contracts",
|
||||||
|
"url": "https://github.com/symfony/contracts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Contracts\\Translation\\": ""
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"/Test/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Generic abstractions related to translation",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"abstractions",
|
||||||
|
"contracts",
|
||||||
|
"decoupling",
|
||||||
|
"interfaces",
|
||||||
|
"interoperability",
|
||||||
|
"standards"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/translation-contracts/tree/v3.5.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-04-18T09:32:20+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "twig/html-extra",
|
"name": "twig/html-extra",
|
||||||
"version": "v3.10.0",
|
"version": "v3.10.0",
|
||||||
|
@ -2385,16 +2963,16 @@
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpstan",
|
"name": "phpstan/phpstan",
|
||||||
"version": "1.11.7",
|
"version": "1.11.9",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpstan/phpstan.git",
|
"url": "https://github.com/phpstan/phpstan.git",
|
||||||
"reference": "52d2bbfdcae7f895915629e4694e9497d0f8e28d"
|
"reference": "e370bcddadaede0c1716338b262346f40d296f82"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/52d2bbfdcae7f895915629e4694e9497d0f8e28d",
|
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e370bcddadaede0c1716338b262346f40d296f82",
|
||||||
"reference": "52d2bbfdcae7f895915629e4694e9497d0f8e28d",
|
"reference": "e370bcddadaede0c1716338b262346f40d296f82",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -2439,17 +3017,13 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-07-06T11:17:41+00:00"
|
"time": "2024-08-01T16:25:18+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "stable",
|
||||||
"stability-flags": {
|
"stability-flags": [],
|
||||||
"flashwave/index": 20,
|
"prefer-stable": false,
|
||||||
"flashwave/sasae": 20,
|
|
||||||
"flashwave/syokuhou": 20
|
|
||||||
},
|
|
||||||
"prefer-stable": true,
|
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": [],
|
"platform": [],
|
||||||
"platform-dev": [],
|
"platform-dev": [],
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use Index\Environment;
|
|
||||||
use Index\Data\DbTools;
|
use Index\Data\DbTools;
|
||||||
use Syokuhou\DbConfig;
|
use Syokuhou\DbConfig;
|
||||||
use Syokuhou\FileConfig;
|
use Syokuhou\FileConfig;
|
||||||
|
@ -19,9 +18,9 @@ define('MSZ_ASSETS', MSZ_ROOT . '/assets');
|
||||||
|
|
||||||
require_once MSZ_ROOT . '/vendor/autoload.php';
|
require_once MSZ_ROOT . '/vendor/autoload.php';
|
||||||
|
|
||||||
Environment::setDebug(MSZ_DEBUG);
|
error_reporting(MSZ_DEBUG ? -1 : 0);
|
||||||
mb_internal_encoding('UTF-8');
|
mb_internal_encoding('UTF-8');
|
||||||
date_default_timezone_set('UTC');
|
date_default_timezone_set('GMT');
|
||||||
|
|
||||||
$cfg = FileConfig::fromFile(MSZ_CONFIG . '/config.cfg');
|
$cfg = FileConfig::fromFile(MSZ_CONFIG . '/config.cfg');
|
||||||
|
|
||||||
|
|
|
@ -4,3 +4,6 @@ parameters:
|
||||||
- src
|
- src
|
||||||
bootstrapFiles:
|
bootstrapFiles:
|
||||||
- misuzu.php
|
- misuzu.php
|
||||||
|
dynamicConstantNames:
|
||||||
|
- MSZ_CLI
|
||||||
|
- MSZ_DEBUG
|
||||||
|
|
|
@ -3,9 +3,10 @@ namespace Misuzu;
|
||||||
|
|
||||||
use stdClass;
|
use stdClass;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\DateTime;
|
|
||||||
use Misuzu\Forum\ForumTopicInfo;
|
use Misuzu\Forum\ForumTopicInfo;
|
||||||
use Misuzu\Parsers\Parser;
|
use Misuzu\Parsers\Parser;
|
||||||
|
use Index\XDateTime;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
|
|
||||||
$authInfo = $msz->getAuthInfo();
|
$authInfo = $msz->getAuthInfo();
|
||||||
if(!$authInfo->isLoggedIn())
|
if(!$authInfo->isLoggedIn())
|
||||||
|
@ -152,11 +153,11 @@ if(!empty($_POST)) {
|
||||||
if($mode === 'create') {
|
if($mode === 'create') {
|
||||||
$postTimeout = $cfg->getInteger('forum.posting.timeout', 5);
|
$postTimeout = $cfg->getInteger('forum.posting.timeout', 5);
|
||||||
if($postTimeout > 0) {
|
if($postTimeout > 0) {
|
||||||
$postTimeoutThreshold = DateTime::now()->modify(sprintf('-%d seconds', $postTimeout));
|
$postTimeoutThreshold = new CarbonImmutable(sprintf('-%d seconds', $postTimeout));
|
||||||
$lastPostCreatedAt = $forumPosts->getUserLastPostCreatedAt($currentUser);
|
$lastPostCreatedAt = $forumPosts->getUserLastPostCreatedAt($currentUser);
|
||||||
|
|
||||||
if($lastPostCreatedAt->isMoreThan($postTimeoutThreshold)) {
|
if(XDateTime::compare($lastPostCreatedAt, $postTimeoutThreshold) > 0) {
|
||||||
$waitSeconds = $postTimeout + ($lastPostCreatedAt->getUnixTimeSeconds() - time());
|
$waitSeconds = $postTimeout + ((int)$lastPostCreatedAt->format('U') - time());
|
||||||
|
|
||||||
$notices[] = sprintf("You're posting too quickly! Please wait %s seconds before posting again.", number_format($waitSeconds));
|
$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.";
|
$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 DateTimeInterface;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\DateTime;
|
|
||||||
use Index\XArray;
|
|
||||||
use Misuzu\Changelog\Changelog;
|
use Misuzu\Changelog\Changelog;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
|
use Index\{XArray,XDateTime};
|
||||||
|
|
||||||
$authInfo = $msz->getAuthInfo();
|
$authInfo = $msz->getAuthInfo();
|
||||||
if(!$authInfo->getPerms('global')->check(Perm::G_CL_CHANGES_MANAGE))
|
if(!$authInfo->getPerms('global')->check(Perm::G_CL_CHANGES_MANAGE))
|
||||||
|
@ -58,8 +58,8 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
||||||
if(empty($createdAt))
|
if(empty($createdAt))
|
||||||
$createdAt = null;
|
$createdAt = null;
|
||||||
else {
|
else {
|
||||||
$createdAt = DateTime::createFromFormat(DateTimeInterface::ATOM, $createdAt . ':00Z');
|
$createdAt = CarbonImmutable::createFromFormat(DateTimeInterface::ATOM, $createdAt . ':00Z');
|
||||||
if($createdAt->getUnixTimeSeconds() < 0)
|
if((int)$createdAt->format('U') < 0)
|
||||||
$createdAt = null;
|
$createdAt = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
||||||
$summary = null;
|
$summary = null;
|
||||||
if($body === $changeInfo->getBody())
|
if($body === $changeInfo->getBody())
|
||||||
$body = null;
|
$body = null;
|
||||||
if($createdAt !== null && $createdAt->equals($changeInfo->getCreatedAt()))
|
if($createdAt !== null && XDateTime::compare($createdAt, $changeInfo->getCreatedAt()) === 0)
|
||||||
$createdAt = null;
|
$createdAt = null;
|
||||||
$updateUserInfo = $userId !== $changeInfo->getUserId();
|
$updateUserInfo = $userId !== $changeInfo->getUserId();
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace Misuzu;
|
||||||
|
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
|
|
||||||
$authInfo = $msz->getAuthInfo();
|
$authInfo = $msz->getAuthInfo();
|
||||||
if(!$authInfo->getPerms('user')->check(Perm::U_BANS_MANAGE))
|
if(!$authInfo->getPerms('user')->check(Perm::U_BANS_MANAGE))
|
||||||
|
@ -56,7 +56,7 @@ while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
||||||
if($expires === -1) {
|
if($expires === -1) {
|
||||||
$expires = null;
|
$expires = null;
|
||||||
} elseif($expires === -2) {
|
} elseif($expires === -2) {
|
||||||
$expires = DateTime::createFromFormat(DateTimeInterface::ATOM, $expiresCustom . ':00Z');
|
$expires = CarbonImmutable::createFromFormat(DateTimeInterface::ATOM, $expiresCustom . ':00Z');
|
||||||
} else {
|
} else {
|
||||||
echo 'Invalid duration specified.';
|
echo 'Invalid duration specified.';
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -5,7 +5,6 @@ use stdClass;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\ByteFormat;
|
use Index\ByteFormat;
|
||||||
use Index\DateTime;
|
|
||||||
use Misuzu\Parsers\Parser;
|
use Misuzu\Parsers\Parser;
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
use Misuzu\Users\Assets\UserAvatarAsset;
|
use Misuzu\Users\Assets\UserAvatarAsset;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
namespace Misuzu\AuditLog;
|
namespace Misuzu\AuditLog;
|
||||||
|
|
||||||
use ValueError;
|
use ValueError;
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
use Index\Net\IPAddress;
|
use Index\Net\IPAddress;
|
||||||
|
|
||||||
|
@ -47,8 +47,8 @@ class AuditLogInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRemoteAddressRaw(): string {
|
public function getRemoteAddressRaw(): string {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Auth;
|
namespace Misuzu\Auth;
|
||||||
|
|
||||||
use Index\XArray;
|
|
||||||
use Misuzu\Auth\SessionInfo;
|
use Misuzu\Auth\SessionInfo;
|
||||||
use Misuzu\Forum\ForumCategoryInfo;
|
use Misuzu\Forum\ForumCategoryInfo;
|
||||||
use Misuzu\Perms\IPermissionResult;
|
use Misuzu\Perms\IPermissionResult;
|
||||||
|
|
63
src/Auth/AuthRpcActions.php
Normal file
63
src/Auth/AuthRpcActions.php
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<?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;
|
namespace Misuzu\Auth;
|
||||||
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
|
use Index\UriBase64;
|
||||||
use Index\IO\MemoryStream;
|
use Index\IO\MemoryStream;
|
||||||
use Index\Serialisation\UriBase64;
|
|
||||||
|
|
||||||
class AuthTokenPacker {
|
class AuthTokenPacker {
|
||||||
private const EPOCH_V2 = 1682985600;
|
private const EPOCH_V2 = 1682985600;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Auth;
|
namespace Misuzu\Auth;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Misuzu\ClientInfo;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
use Index\Net\IPAddress;
|
use Index\Net\IPAddress;
|
||||||
use Misuzu\ClientInfo;
|
|
||||||
|
|
||||||
class LoginAttemptInfo {
|
class LoginAttemptInfo {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -57,8 +57,8 @@ class LoginAttemptInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUserAgentString(): string {
|
public function getUserAgentString(): string {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Auth;
|
namespace Misuzu\Auth;
|
||||||
|
|
||||||
use Index\TimeSpan;
|
|
||||||
use Index\Data\DbStatementCache;
|
use Index\Data\DbStatementCache;
|
||||||
use Index\Data\IDbConnection;
|
use Index\Data\IDbConnection;
|
||||||
use Index\Net\IPAddress;
|
use Index\Net\IPAddress;
|
||||||
|
@ -23,14 +22,12 @@ class LoginAttempts {
|
||||||
?bool $success = null,
|
?bool $success = null,
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
IPAddress|string|null $remoteAddr = null,
|
IPAddress|string|null $remoteAddr = null,
|
||||||
TimeSpan|int|null $timeRange = null
|
int|null $timeRange = null
|
||||||
): int {
|
): int {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
if($remoteAddr instanceof IPAddress)
|
if($remoteAddr instanceof IPAddress)
|
||||||
$remoteAddr = (string)$remoteAddr;
|
$remoteAddr = (string)$remoteAddr;
|
||||||
if($timeRange instanceof TimeSpan)
|
|
||||||
$timeRange = (int)$timeRange->totalSeconds();
|
|
||||||
|
|
||||||
$hasSuccess = $success !== null;
|
$hasSuccess = $success !== null;
|
||||||
$hasUserInfo = $userInfo !== null;
|
$hasUserInfo = $userInfo !== null;
|
||||||
|
@ -81,15 +78,13 @@ class LoginAttempts {
|
||||||
?bool $success = null,
|
?bool $success = null,
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
IPAddress|string|null $remoteAddr = null,
|
IPAddress|string|null $remoteAddr = null,
|
||||||
TimeSpan|int|null $timeRange = null,
|
int|null $timeRange = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): iterable {
|
): iterable {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
if($remoteAddr instanceof IPAddress)
|
if($remoteAddr instanceof IPAddress)
|
||||||
$remoteAddr = (string)$remoteAddr;
|
$remoteAddr = (string)$remoteAddr;
|
||||||
if($timeRange instanceof TimeSpan)
|
|
||||||
$timeRange = (int)$timeRange->totalSeconds();
|
|
||||||
|
|
||||||
$hasSuccess = $success !== null;
|
$hasSuccess = $success !== null;
|
||||||
$hasUserInfo = $userInfo !== null;
|
$hasUserInfo = $userInfo !== null;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Auth;
|
namespace Misuzu\Auth;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
use Index\Net\IPAddress;
|
use Index\Net\IPAddress;
|
||||||
|
|
||||||
|
@ -36,16 +36,16 @@ class RecoveryTokenInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getExpiresTime(): int {
|
public function getExpiresTime(): int {
|
||||||
return $this->created + self::LIFETIME;
|
return $this->created + self::LIFETIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getExpiresAt(): DateTime {
|
public function getExpiresAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created + self::LIFETIME);
|
return CarbonImmutable::createFromTimestampUTC($this->getExpiresTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasExpired(): bool {
|
public function hasExpired(): bool {
|
||||||
|
|
|
@ -3,10 +3,10 @@ namespace Misuzu\Auth;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
|
use Index\Base32;
|
||||||
use Index\Data\DbStatementCache;
|
use Index\Data\DbStatementCache;
|
||||||
use Index\Data\IDbConnection;
|
use Index\Data\IDbConnection;
|
||||||
use Index\Net\IPAddress;
|
use Index\Net\IPAddress;
|
||||||
use Index\Serialisation\Base32;
|
|
||||||
use Misuzu\ClientInfo;
|
use Misuzu\ClientInfo;
|
||||||
use Misuzu\Pagination;
|
use Misuzu\Pagination;
|
||||||
use Misuzu\Users\UserInfo;
|
use Misuzu\Users\UserInfo;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Auth;
|
namespace Misuzu\Auth;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Misuzu\ClientInfo;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
use Index\Net\IPAddress;
|
use Index\Net\IPAddress;
|
||||||
use Misuzu\ClientInfo;
|
|
||||||
|
|
||||||
class SessionInfo {
|
class SessionInfo {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -91,8 +91,8 @@ class SessionInfo {
|
||||||
return $this->expires;
|
return $this->expires;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getExpiresAt(): DateTime {
|
public function getExpiresAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->expires);
|
return CarbonImmutable::createFromTimestampUTC($this->expires);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function shouldBumpExpires(): bool {
|
public function shouldBumpExpires(): bool {
|
||||||
|
@ -107,8 +107,8 @@ class SessionInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasLastActive(): bool {
|
public function hasLastActive(): bool {
|
||||||
|
@ -119,7 +119,7 @@ class SessionInfo {
|
||||||
return $this->lastActive;
|
return $this->lastActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLastActiveAt(): ?DateTime {
|
public function getLastActiveAt(): ?CarbonImmutable {
|
||||||
return $this->lastActive === null ? null : DateTime::fromUnixTimeSeconds($this->lastActive);
|
return $this->lastActive === null ? null : CarbonImmutable::createFromTimestampUTC($this->lastActive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use Index\Security\CSRFP;
|
use Index\CSRFP;
|
||||||
|
|
||||||
final class CSRF {
|
final class CSRF {
|
||||||
private static CSRFP $instance;
|
private static CSRFP $instance;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Changelog;
|
namespace Misuzu\Changelog;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class ChangeInfo {
|
class ChangeInfo {
|
||||||
|
@ -53,8 +53,8 @@ class ChangeInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDate(): string {
|
public function getDate(): string {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
namespace Misuzu\Changelog;
|
namespace Misuzu\Changelog;
|
||||||
|
|
||||||
use Stringable;
|
use Stringable;
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class ChangeTagInfo implements Stringable {
|
class ChangeTagInfo implements Stringable {
|
||||||
|
@ -38,16 +38,16 @@ class ChangeTagInfo implements Stringable {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getArchivedTime(): int {
|
public function getArchivedTime(): int {
|
||||||
return $this->archived;
|
return $this->archived;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getArchivedAt(): DateTime {
|
public function getArchivedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->archived);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isArchived(): bool {
|
public function isArchived(): bool {
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace Misuzu\Changelog;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\DateTime;
|
use DateTimeInterface;
|
||||||
use Index\Data\DbStatementCache;
|
use Index\Data\DbStatementCache;
|
||||||
use Index\Data\DbTools;
|
use Index\Data\DbTools;
|
||||||
use Index\Data\IDbConnection;
|
use Index\Data\IDbConnection;
|
||||||
|
@ -66,13 +66,13 @@ class Changelog {
|
||||||
|
|
||||||
public function countChanges(
|
public function countChanges(
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
DateTime|int|null $dateTime = null,
|
DateTimeInterface|int|null $dateTime = null,
|
||||||
?array $tags = null
|
?array $tags = null
|
||||||
): int {
|
): int {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
if($dateTime instanceof DateTime)
|
if($dateTime instanceof DateTimeInterface)
|
||||||
$dateTime = $dateTime->getUnixTimeSeconds();
|
$dateTime = (int)$dateTime->format('U');
|
||||||
|
|
||||||
$args = 0;
|
$args = 0;
|
||||||
$hasUserInfo = $userInfo !== null;
|
$hasUserInfo = $userInfo !== null;
|
||||||
|
@ -118,14 +118,14 @@ class Changelog {
|
||||||
|
|
||||||
public function getChanges(
|
public function getChanges(
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
DateTime|int|null $dateTime = null,
|
DateTimeInterface|int|null $dateTime = null,
|
||||||
?array $tags = null,
|
?array $tags = null,
|
||||||
?Pagination $pagination = null
|
?Pagination $pagination = null
|
||||||
): iterable {
|
): iterable {
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
if($dateTime instanceof DateTime)
|
if($dateTime instanceof DateTimeInterface)
|
||||||
$dateTime = $dateTime->getUnixTimeSeconds();
|
$dateTime = (int)$dateTime->format('U');
|
||||||
|
|
||||||
$args = 0;
|
$args = 0;
|
||||||
$hasUserInfo = $userInfo !== null;
|
$hasUserInfo = $userInfo !== null;
|
||||||
|
@ -189,14 +189,14 @@ class Changelog {
|
||||||
string $summary,
|
string $summary,
|
||||||
string $body = '',
|
string $body = '',
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
DateTime|int|null $createdAt = null
|
DateTimeInterface|int|null $createdAt = null
|
||||||
): ChangeInfo {
|
): ChangeInfo {
|
||||||
if(is_string($action))
|
if(is_string($action))
|
||||||
$action = self::convertToActionId($action);
|
$action = self::convertToActionId($action);
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
if($createdAt instanceof DateTime)
|
if($createdAt instanceof DateTimeInterface)
|
||||||
$createdAt = $createdAt->getUnixTimeSeconds();
|
$createdAt = (int)$createdAt->format('U');
|
||||||
|
|
||||||
$summary = trim($summary);
|
$summary = trim($summary);
|
||||||
if(empty($summary))
|
if(empty($summary))
|
||||||
|
@ -233,7 +233,7 @@ class Changelog {
|
||||||
?string $body = null,
|
?string $body = null,
|
||||||
bool $updateUserInfo = false,
|
bool $updateUserInfo = false,
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
DateTime|int|null $createdAt = null
|
DateTimeInterface|int|null $createdAt = null
|
||||||
): void {
|
): void {
|
||||||
if($infoOrId instanceof ChangeInfo)
|
if($infoOrId instanceof ChangeInfo)
|
||||||
$infoOrId = $infoOrId->getId();
|
$infoOrId = $infoOrId->getId();
|
||||||
|
@ -242,8 +242,8 @@ class Changelog {
|
||||||
$action = self::convertToActionId($action);
|
$action = self::convertToActionId($action);
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
if($createdAt instanceof DateTime)
|
if($createdAt instanceof DateTimeInterface)
|
||||||
$createdAt = $createdAt->getUnixTimeSeconds();
|
$createdAt = (int)$createdAt->format('U');
|
||||||
|
|
||||||
if($summary !== null) {
|
if($summary !== null) {
|
||||||
$summary = trim($summary);
|
$summary = trim($summary);
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Comments;
|
namespace Misuzu\Comments;
|
||||||
|
|
||||||
use Index\DateTime;
|
|
||||||
use Index\Data\IDbResult;
|
|
||||||
use Misuzu\Users\UserInfo;
|
use Misuzu\Users\UserInfo;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class CommentsCategoryInfo {
|
class CommentsCategoryInfo {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -54,16 +54,17 @@ class CommentsCategoryInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLockedTime(): ?int {
|
public function getLockedTime(): ?int {
|
||||||
return $this->locked;
|
return $this->locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLockedAt(): ?DateTime {
|
public function getLockedAt(): ?CarbonImmutable {
|
||||||
return $this->locked === null ? null : DateTime::fromUnixTimeSeconds($this->locked);
|
return $this->locked === null ? null : CarbonImmutable::createFromTimestampUTC($this->locked);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isLocked(): bool {
|
public function isLocked(): bool {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Comments;
|
namespace Misuzu\Comments;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class CommentsPostInfo {
|
class CommentsPostInfo {
|
||||||
|
@ -86,16 +86,16 @@ class CommentsPostInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPinnedTime(): ?int {
|
public function getPinnedTime(): ?int {
|
||||||
return $this->pinned;
|
return $this->pinned;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPinnedAt(): DateTime {
|
public function getPinnedAt(): ?CarbonImmutable {
|
||||||
return $this->pinned === null ? null : DateTime::fromUnixTimeSeconds($this->pinned);
|
return $this->pinned === null ? null : CarbonImmutable::createFromTimestampUTC($this->pinned);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isPinned(): bool {
|
public function isPinned(): bool {
|
||||||
|
@ -106,8 +106,8 @@ class CommentsPostInfo {
|
||||||
return $this->updated;
|
return $this->updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUpdatedAt(): DateTime {
|
public function getUpdatedAt(): ?CarbonImmutable {
|
||||||
return $this->updated === null ? null : DateTime::fromUnixTimeSeconds($this->updated);
|
return $this->updated === null ? null : CarbonImmutable::createFromTimestampUTC($this->updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isEdited(): bool {
|
public function isEdited(): bool {
|
||||||
|
@ -118,8 +118,8 @@ class CommentsPostInfo {
|
||||||
return $this->deleted;
|
return $this->deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDeletedAt(): DateTime {
|
public function getDeletedAt(): ?CarbonImmutable {
|
||||||
return $this->deleted === null ? null : DateTime::fromUnixTimeSeconds($this->deleted);
|
return $this->deleted === null ? null : CarbonImmutable::createFromTimestampUTC($this->deleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isDeleted(): bool {
|
public function isDeleted(): bool {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Counters;
|
namespace Misuzu\Counters;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class CounterInfo {
|
class CounterInfo {
|
||||||
|
@ -31,7 +31,7 @@ class CounterInfo {
|
||||||
return $this->updated;
|
return $this->updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUpdatedAt(): DateTime {
|
public function getUpdatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->updated);
|
return CarbonImmutable::createFromTimestampUTC($this->updated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Forum;
|
namespace Misuzu\Forum;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Colour\Colour;
|
use Index\Colour\Colour;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
|
@ -176,8 +176,8 @@ class ForumCategoryInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isArchived(): bool {
|
public function isArchived(): bool {
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Forum;
|
namespace Misuzu\Forum;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Misuzu\Parsers\Parser;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
|
use Index\XDateTime;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
use Index\Net\IPAddress;
|
use Index\Net\IPAddress;
|
||||||
use Misuzu\Parsers\Parser;
|
|
||||||
|
|
||||||
class ForumPostInfo {
|
class ForumPostInfo {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -93,16 +94,17 @@ class ForumPostInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ?DateTime $markAsEditedThreshold = null;
|
private static ?CarbonImmutable $markAsEditedThreshold = null;
|
||||||
|
|
||||||
public function shouldMarkAsEdited(): bool {
|
public function shouldMarkAsEdited(): bool {
|
||||||
if(self::$markAsEditedThreshold === null)
|
if(self::$markAsEditedThreshold === null)
|
||||||
self::$markAsEditedThreshold = DateTime::now()->modify('-5 minutes');
|
self::$markAsEditedThreshold = new CarbonImmutable('-5 minutes');
|
||||||
|
|
||||||
return $this->getCreatedAt()->isLessThan(self::$markAsEditedThreshold);
|
return XDateTime::compare($this->getCreatedAt(), self::$markAsEditedThreshold) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isEdited(): bool {
|
public function isEdited(): bool {
|
||||||
|
@ -113,16 +115,17 @@ class ForumPostInfo {
|
||||||
return $this->edited;
|
return $this->edited;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEditedAt(): ?DateTime {
|
public function getEditedAt(): ?CarbonImmutable {
|
||||||
return $this->edited === null ? null : DateTime::fromUnixTimeSeconds($this->edited);
|
return $this->edited === null ? null : CarbonImmutable::createFromTimestampUTC($this->edited);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ?DateTime $canBeDeletedThreshold = null;
|
private static ?CarbonImmutable $canBeDeletedThreshold = null;
|
||||||
|
|
||||||
public function canBeDeleted(): bool {
|
public function canBeDeleted(): bool {
|
||||||
if(self::$canBeDeletedThreshold === null)
|
if(self::$canBeDeletedThreshold === null)
|
||||||
self::$canBeDeletedThreshold = DateTime::now()->modify('-1 week');
|
self::$canBeDeletedThreshold = new CarbonImmutable('-1 week');
|
||||||
|
|
||||||
return $this->getCreatedAt()->isMoreThanOrEqual(self::$canBeDeletedThreshold);
|
return XDateTime::compare($this->getCreatedAt(), self::$canBeDeletedThreshold) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isDeleted(): bool {
|
public function isDeleted(): bool {
|
||||||
|
@ -133,7 +136,7 @@ class ForumPostInfo {
|
||||||
return $this->deleted;
|
return $this->deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDeletedAt(): ?DateTime {
|
public function getDeletedAt(): ?CarbonImmutable {
|
||||||
return $this->deleted === null ? null : DateTime::fromUnixTimeSeconds($this->deleted);
|
return $this->deleted === null ? null : CarbonImmutable::createFromTimestampUTC($this->deleted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace Misuzu\Forum;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\DbStatementCache;
|
use Index\Data\DbStatementCache;
|
||||||
use Index\Data\DbTools;
|
use Index\Data\DbTools;
|
||||||
use Index\Data\IDbConnection;
|
use Index\Data\IDbConnection;
|
||||||
|
@ -395,8 +395,8 @@ class ForumPosts {
|
||||||
return $result->getInteger(0);
|
return $result->getInteger(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUserLastPostCreatedAt(UserInfo|string $userInfo): DateTime {
|
public function getUserLastPostCreatedAt(UserInfo|string $userInfo): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->getUserLastPostCreatedTime($userInfo));
|
return CarbonImmutable::createFromTimestampUTC($this->getUserLastPostCreatedTime($userInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generatePostRankings(
|
public function generatePostRankings(
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Forum;
|
namespace Misuzu\Forum;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
|
use Index\XDateTime;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class ForumTopicInfo {
|
class ForumTopicInfo {
|
||||||
|
@ -136,25 +137,25 @@ class ForumTopicInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ?DateTime $lastActiveAt = null;
|
private static ?CarbonImmutable $lastActiveAt = null;
|
||||||
|
|
||||||
public function isActive(): bool {
|
public function isActive(): bool {
|
||||||
if(self::$lastActiveAt === null)
|
if(self::$lastActiveAt === null)
|
||||||
self::$lastActiveAt = DateTime::now()->modify('-1 month');
|
self::$lastActiveAt = new CarbonImmutable('-1 month');
|
||||||
|
|
||||||
return $this->getBumpedAt()->isMoreThanOrEqual(self::$lastActiveAt);
|
return XDateTime::compare($this->getBumpedAt(), self::$lastActiveAt) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBumpedTime(): int {
|
public function getBumpedTime(): int {
|
||||||
return $this->bumped;
|
return $this->bumped;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBumpedAt(): DateTime {
|
public function getBumpedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->bumped);
|
return CarbonImmutable::createFromTimestampUTC($this->bumped);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isDeleted(): bool {
|
public function isDeleted(): bool {
|
||||||
|
@ -165,8 +166,8 @@ class ForumTopicInfo {
|
||||||
return $this->deleted;
|
return $this->deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDeletedAt(): ?DateTime {
|
public function getDeletedAt(): ?CarbonImmutable {
|
||||||
return $this->deleted === null ? null : DateTime::fromUnixTimeSeconds($this->deleted);
|
return $this->deleted === null ? null : CarbonImmutable::createFromTimestampUTC($this->deleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isLocked(): bool {
|
public function isLocked(): bool {
|
||||||
|
@ -177,7 +178,7 @@ class ForumTopicInfo {
|
||||||
return $this->locked;
|
return $this->locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLockedAt(): ?DateTime {
|
public function getLockedAt(): ?CarbonImmutable {
|
||||||
return $this->locked === null ? null : DateTime::fromUnixTimeSeconds($this->locked);
|
return $this->locked === null ? null : CarbonImmutable::createFromTimestampUTC($this->locked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Forum;
|
namespace Misuzu\Forum;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class ForumTopicRedirectInfo {
|
class ForumTopicRedirectInfo {
|
||||||
|
@ -41,7 +41,7 @@ class ForumTopicRedirectInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +1,36 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Hanyuu;
|
namespace Misuzu\Hanyuu;
|
||||||
|
|
||||||
use stdClass;
|
|
||||||
use RuntimeException;
|
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\CSRF;
|
||||||
use Misuzu\Auth\{AuthContext,AuthInfo,Sessions};
|
use Misuzu\Auth\AuthContext;
|
||||||
use Misuzu\URLs\URLRegistry;
|
use Misuzu\URLs\URLRegistry;
|
||||||
use Misuzu\Users\{UsersContext,UserInfo};
|
use Misuzu\Users\{UsersContext,UserInfo};
|
||||||
|
use Aiwass\Server\{RpcActionHandler,RpcProcedure};
|
||||||
|
use Index\Colour\Colour;
|
||||||
|
use Syokuhou\IConfig;
|
||||||
|
|
||||||
final class HanyuuRoutes extends RouteHandler {
|
final class HanyuuRpcActions extends RpcActionHandler {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private IConfig $config,
|
private $getBaseUrl,
|
||||||
private IConfig $impersonateConfig, // this sucks lol
|
private IConfig $impersonateConfig,
|
||||||
private URLRegistry $urls,
|
private URLRegistry $urls,
|
||||||
private UsersContext $usersCtx,
|
private UsersContext $usersCtx,
|
||||||
private AuthContext $authCtx,
|
private AuthContext $authCtx
|
||||||
private AuthInfo $authInfo
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
private function getEndpoint(): string {
|
private static function createPayload(string $name, array $attrs = []): array {
|
||||||
return $this->config->getString('endpoint');
|
$payload = ['name' => $name, 'attrs' => []];
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
foreach($attrs as $name => $value) {
|
||||||
if($value === null)
|
if($value === null)
|
||||||
continue;
|
continue;
|
||||||
$payload->attrs[(string)$name] = $value;
|
$payload['attrs'][(string)$name] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $payload;
|
return $payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function createErrorPayload(string $code, ?string $text = null): object {
|
private static function createErrorPayload(string $code, ?string $text = null): array {
|
||||||
$attrs = ['code' => $code];
|
$attrs = ['code' => $code];
|
||||||
if($text !== null && $text !== '')
|
if($text !== null && $text !== '')
|
||||||
$attrs['text'] = $text;
|
$attrs['text'] = $text;
|
||||||
|
@ -51,42 +38,6 @@ final class HanyuuRoutes extends RouteHandler {
|
||||||
return self::createPayload('error', $attrs);
|
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 {
|
private function canImpersonateUserId(UserInfo $impersonator, string $targetId): bool {
|
||||||
if($impersonator->isSuperUser())
|
if($impersonator->isSuperUser())
|
||||||
return true;
|
return true;
|
||||||
|
@ -98,18 +49,15 @@ final class HanyuuRoutes extends RouteHandler {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[HttpPost('/_hanyuu/auth-check')]
|
#[RpcProcedure('mszhau:authCheck')]
|
||||||
public function postCheckAuth($response, $request) {
|
public function procAuthCheck(string $method, string $remoteAddr, string $token, string $avatars = '') {
|
||||||
$content = $request->getContent();
|
|
||||||
$method = (string)$content->getParam('method');
|
|
||||||
if($method !== 'Misuzu')
|
if($method !== 'Misuzu')
|
||||||
return self::createErrorPayload('auth:check:method', 'Requested auth method is not supported.');
|
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)
|
if(filter_var($remoteAddr, FILTER_VALIDATE_IP) === false)
|
||||||
return self::createErrorPayload('auth:check:remote_addr', 'Provided remote address is not in a valid format.');
|
return self::createErrorPayload('auth:check:remote_addr', 'Provided remote address is not in a valid format.');
|
||||||
|
|
||||||
$avatarResolutions = trim((string)$content->getParam('avatars'));
|
$avatarResolutions = trim($avatars);
|
||||||
if($avatarResolutions === '') {
|
if($avatarResolutions === '') {
|
||||||
$avatarResolutions = [];
|
$avatarResolutions = [];
|
||||||
} else {
|
} else {
|
||||||
|
@ -122,11 +70,12 @@ final class HanyuuRoutes extends RouteHandler {
|
||||||
$avatarResolutions = array_unique($avatarResolutions);
|
$avatarResolutions = array_unique($avatarResolutions);
|
||||||
}
|
}
|
||||||
|
|
||||||
$loginUrl = $this->getEndpoint() . $this->urls->format('auth-login');
|
$baseUrl = ($this->getBaseUrl)();
|
||||||
$registerUrl = $this->getEndpoint() . $this->urls->format('auth-register');
|
$loginUrl = $baseUrl . $this->urls->format('auth-login');
|
||||||
|
$registerUrl = $baseUrl . $this->urls->format('auth-register');
|
||||||
|
|
||||||
$tokenPacker = $this->authCtx->createAuthTokenPacker();
|
$tokenPacker = $this->authCtx->createAuthTokenPacker();
|
||||||
$tokenInfo = $tokenPacker->unpack(trim((string)$content->getParam('token')));
|
$tokenInfo = $tokenPacker->unpack(trim($token));
|
||||||
if($tokenInfo->isEmpty())
|
if($tokenInfo->isEmpty())
|
||||||
return self::createPayload('auth:check:fail', ['reason' => 'empty', 'login_url' => $loginUrl, 'register_url' => $registerUrl]);
|
return self::createPayload('auth:check:fail', ['reason' => 'empty', 'login_url' => $loginUrl, 'register_url' => $registerUrl]);
|
||||||
|
|
||||||
|
@ -156,6 +105,7 @@ final class HanyuuRoutes extends RouteHandler {
|
||||||
|
|
||||||
$response = [];
|
$response = [];
|
||||||
$response['session'] = [
|
$response['session'] = [
|
||||||
|
'token' => $sessionInfo->getToken(),
|
||||||
'created_at' => $sessionInfo->getCreatedTime(),
|
'created_at' => $sessionInfo->getCreatedTime(),
|
||||||
'expires_at' => $sessionInfo->getExpiresTime(),
|
'expires_at' => $sessionInfo->getExpiresTime(),
|
||||||
'lifetime_extends' => $sessionInfo->shouldBumpExpires(),
|
'lifetime_extends' => $sessionInfo->shouldBumpExpires(),
|
||||||
|
@ -173,9 +123,9 @@ final class HanyuuRoutes extends RouteHandler {
|
||||||
'remaining_str' => $banInfo->getRemainingString(),
|
'remaining_str' => $banInfo->getRemainingString(),
|
||||||
];
|
];
|
||||||
|
|
||||||
$gatherRequestedAvatars = function($userInfo) use ($avatarResolutions) {
|
$gatherRequestedAvatars = function($userInfo) use ($avatarResolutions, $baseUrl) {
|
||||||
$formatAvatarUrl = fn($res = 0) => (
|
$formatAvatarUrl = fn($res = 0) => (
|
||||||
$this->getEndpoint() . $this->urls->format('user-avatar', ['user' => $userInfo->getId(), 'res' => $res])
|
$baseUrl . $this->urls->format('user-avatar', ['user' => $userInfo->getId(), 'res' => $res])
|
||||||
);
|
);
|
||||||
|
|
||||||
$avatars = ['original' => $formatAvatarUrl()];
|
$avatars = ['original' => $formatAvatarUrl()];
|
||||||
|
@ -195,7 +145,7 @@ final class HanyuuRoutes extends RouteHandler {
|
||||||
'country_code' => $userInfo->getCountryCode(),
|
'country_code' => $userInfo->getCountryCode(),
|
||||||
'is_deleted' => $userInfo->isDeleted(),
|
'is_deleted' => $userInfo->isDeleted(),
|
||||||
'has_totp' => $userInfo->hasTOTPKey(),
|
'has_totp' => $userInfo->hasTOTPKey(),
|
||||||
'profile_url' => $this->getEndpoint() . $this->urls->format('user-profile', ['user' => $userInfo->getId()]),
|
'profile_url' => $baseUrl . $this->urls->format('user-profile', ['user' => $userInfo->getId()]),
|
||||||
'avatars' => $gatherRequestedAvatars($userInfo),
|
'avatars' => $gatherRequestedAvatars($userInfo),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -204,7 +154,7 @@ final class HanyuuRoutes extends RouteHandler {
|
||||||
$response['guise'] = $extractUserInfo($userInfoReal);
|
$response['guise'] = $extractUserInfo($userInfoReal);
|
||||||
|
|
||||||
$csrfp = CSRF::create($sessionInfo->getToken());
|
$csrfp = CSRF::create($sessionInfo->getToken());
|
||||||
$response['guise']['revert_url'] = $this->getEndpoint() . $this->urls->format('auth-revert', ['csrf' => $csrfp->createToken()]);
|
$response['guise']['revert_url'] = $baseUrl . $this->urls->format('auth-revert', ['csrf' => $csrfp->createToken()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::createPayload('auth:check:success', $response);
|
return self::createPayload('auth:check:success', $response);
|
|
@ -2,7 +2,7 @@
|
||||||
namespace Misuzu\Home;
|
namespace Misuzu\Home;
|
||||||
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\DateTime;
|
use Index\XDateTime;
|
||||||
use Index\Data\{DbTools,IDbConnection};
|
use Index\Data\{DbTools,IDbConnection};
|
||||||
use Index\Http\Routing\{HttpGet,RouteHandler};
|
use Index\Http\Routing\{HttpGet,RouteHandler};
|
||||||
use Syokuhou\IConfig;
|
use Syokuhou\IConfig;
|
||||||
|
@ -167,7 +167,7 @@ class HomeRoutes extends RouteHandler {
|
||||||
$stats['users:online:recent'] = count($onlineUserInfos);
|
$stats['users:online:recent'] = count($onlineUserInfos);
|
||||||
|
|
||||||
$birthdays = [];
|
$birthdays = [];
|
||||||
$birthdayInfos = $this->usersCtx->getUsers()->getUsers(deleted: false, birthdate: DateTime::now(), orderBy: 'random');
|
$birthdayInfos = $this->usersCtx->getUsers()->getUsers(deleted: false, birthdate: XDateTime::now(), orderBy: 'random');
|
||||||
foreach($birthdayInfos as $birthdayInfo)
|
foreach($birthdayInfos as $birthdayInfo)
|
||||||
$birthdays[] = [
|
$birthdays[] = [
|
||||||
'info' => $birthdayInfo,
|
'info' => $birthdayInfo,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Messages;
|
namespace Misuzu\Messages;
|
||||||
|
|
||||||
use Index\DateTime;
|
|
||||||
use Index\Data\IDbResult;
|
|
||||||
use Misuzu\Parsers\Parser;
|
use Misuzu\Parsers\Parser;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class MessageInfo {
|
class MessageInfo {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -98,8 +98,8 @@ class MessageInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isSent(): bool {
|
public function isSent(): bool {
|
||||||
|
@ -110,8 +110,8 @@ class MessageInfo {
|
||||||
return $this->sent;
|
return $this->sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSentAt(): ?DateTime {
|
public function getSentAt(): ?CarbonImmutable {
|
||||||
return $this->sent === null ? null : DateTime::fromUnixTimeSeconds($this->sent);
|
return $this->sent === null ? null : CarbonImmutable::createFromTimestampUTC($this->sent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isRead(): bool {
|
public function isRead(): bool {
|
||||||
|
@ -122,8 +122,8 @@ class MessageInfo {
|
||||||
return $this->read;
|
return $this->read;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getReadAt(): ?DateTime {
|
public function getReadAt(): ?CarbonImmutable {
|
||||||
return $this->read === null ? null : DateTime::fromUnixTimeSeconds($this->read);
|
return $this->read === null ? null : CarbonImmutable::createFromTimestampUTC($this->read);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isDeleted(): bool {
|
public function isDeleted(): bool {
|
||||||
|
@ -134,8 +134,8 @@ class MessageInfo {
|
||||||
return $this->deleted;
|
return $this->deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDeletedAt(): ?DateTime {
|
public function getDeletedAt(): ?CarbonImmutable {
|
||||||
return $this->deleted === null ? null : DateTime::fromUnixTimeSeconds($this->deleted);
|
return $this->deleted === null ? null : CarbonImmutable::createFromTimestampUTC($this->deleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDisplayTime(): int {
|
public function getDisplayTime(): int {
|
||||||
|
@ -144,7 +144,7 @@ class MessageInfo {
|
||||||
return $this->getCreatedTime();
|
return $this->getCreatedTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDisplayAt(): DateTime {
|
public function getDisplayAt(): CarbonImmutable {
|
||||||
if($this->isSent())
|
if($this->isSent())
|
||||||
return $this->getSentAt();
|
return $this->getSentAt();
|
||||||
return $this->getCreatedAt();
|
return $this->getCreatedAt();
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace Misuzu\Messages;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\DateTime;
|
use DateTimeInterface;
|
||||||
use Index\Data\{DbStatementCache,DbTools,IDbConnection};
|
use Index\Data\{DbStatementCache,DbTools,IDbConnection};
|
||||||
use Misuzu\Pagination;
|
use Misuzu\Pagination;
|
||||||
use Misuzu\Users\UserInfo;
|
use Misuzu\Users\UserInfo;
|
||||||
|
@ -189,8 +189,8 @@ class MessagesDatabase {
|
||||||
string $body,
|
string $body,
|
||||||
int $parser,
|
int $parser,
|
||||||
MessageInfo|string|null $replyTo = null,
|
MessageInfo|string|null $replyTo = null,
|
||||||
DateTime|int|null $sentAt = null,
|
DateTimeInterface|int|null $sentAt = null,
|
||||||
DateTime|int|null $readAt = null
|
DateTimeInterface|int|null $readAt = null
|
||||||
): MessageInfo {
|
): 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 = $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);
|
$stmt->addParameter(1, $messageId);
|
||||||
|
@ -201,8 +201,8 @@ class MessagesDatabase {
|
||||||
$stmt->addParameter(6, $title);
|
$stmt->addParameter(6, $title);
|
||||||
$stmt->addParameter(7, $body);
|
$stmt->addParameter(7, $body);
|
||||||
$stmt->addParameter(8, $parser);
|
$stmt->addParameter(8, $parser);
|
||||||
$stmt->addParameter(9, $sentAt instanceof DateTime ? $sentAt->getUnixTimeSeconds() : $sentAt);
|
$stmt->addParameter(9, $sentAt instanceof DateTimeInterface ? (int)$sentAt->format('U') : $sentAt);
|
||||||
$stmt->addParameter(10, $readAt instanceof DateTime ? $readAt->getUnixTimeSeconds() : $readAt);
|
$stmt->addParameter(10, $readAt instanceof DateTimeInterface ? (int)$readAt->format('U') : $readAt);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
return $this->getMessageInfo($ownerInfo, $messageId);
|
return $this->getMessageInfo($ownerInfo, $messageId);
|
||||||
|
@ -214,8 +214,8 @@ class MessagesDatabase {
|
||||||
?string $title = null,
|
?string $title = null,
|
||||||
?string $body = null,
|
?string $body = null,
|
||||||
?int $parser = null,
|
?int $parser = null,
|
||||||
DateTime|int|null|false $sentAt = false,
|
DateTimeInterface|int|null|false $sentAt = false,
|
||||||
DateTime|int|null|false $readAt = false
|
DateTimeInterface|int|null|false $readAt = false
|
||||||
): void {
|
): void {
|
||||||
$setQuery = [];
|
$setQuery = [];
|
||||||
$setValues = [];
|
$setValues = [];
|
||||||
|
@ -249,12 +249,12 @@ class MessagesDatabase {
|
||||||
|
|
||||||
if($sentAt !== false) {
|
if($sentAt !== false) {
|
||||||
$setQuery[] = 'msg_sent = FROM_UNIXTIME(?)';
|
$setQuery[] = 'msg_sent = FROM_UNIXTIME(?)';
|
||||||
$setValues[] = $sentAt instanceof DateTime ? $sentAt->getUnixTimeSeconds() : $sentAt;
|
$setValues[] = $sentAt instanceof DateTimeInterface ? (int)$sentAt->format('U') : $sentAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($readAt !== false) {
|
if($readAt !== false) {
|
||||||
$setQuery[] = 'msg_read = FROM_UNIXTIME(?)';
|
$setQuery[] = 'msg_read = FROM_UNIXTIME(?)';
|
||||||
$setValues[] = $readAt instanceof DateTime ? $readAt->getUnixTimeSeconds() : $readAt;
|
$setValues[] = $readAt instanceof DateTimeInterface ? (int)$readAt->format('U') : $readAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(empty($whereQuery))
|
if(empty($whereQuery))
|
||||||
|
|
|
@ -357,7 +357,6 @@ class MessagesRoutes extends RouteHandler {
|
||||||
'error' => [
|
'error' => [
|
||||||
'name' => 'msgs:recipient_invalid',
|
'name' => 'msgs:recipient_invalid',
|
||||||
'text' => 'Name of the recipient was incorrectly formatted.',
|
'text' => 'Name of the recipient was incorrectly formatted.',
|
||||||
'jeff' => $recipient,
|
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
} catch(RuntimeException $ex) {
|
} catch(RuntimeException $ex) {
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
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\Template;
|
||||||
use Misuzu\Auth\{AuthContext,AuthInfo};
|
use Misuzu\Auth\{AuthContext,AuthInfo};
|
||||||
use Misuzu\AuditLog\AuditLog;
|
use Misuzu\AuditLog\AuditLog;
|
||||||
|
@ -20,6 +15,12 @@ use Misuzu\Perms\Permissions;
|
||||||
use Misuzu\Profile\ProfileFields;
|
use Misuzu\Profile\ProfileFields;
|
||||||
use Misuzu\URLs\URLRegistry;
|
use Misuzu\URLs\URLRegistry;
|
||||||
use Misuzu\Users\{UsersContext,UserInfo};
|
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
|
// this class should function as the root for everything going forward
|
||||||
// no more magical static classes that are just kind of assumed to exist
|
// no more magical static classes that are just kind of assumed to exist
|
||||||
|
@ -191,7 +192,7 @@ class MisuzuContext {
|
||||||
['eeprom.appmsgs:s', '', 'eeprom_app_messages'],
|
['eeprom.appmsgs:s', '', 'eeprom_app_messages'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$isDebug = Environment::isDebug();
|
$isDebug = MSZ_DEBUG;
|
||||||
$globals['site_info'] = $this->siteInfo;
|
$globals['site_info'] = $this->siteInfo;
|
||||||
$globals['auth_info'] = $this->authInfo;
|
$globals['auth_info'] = $this->authInfo;
|
||||||
$globals['active_ban_info'] = $this->usersCtx->tryGetActiveBan($this->authInfo->getUserInfo());
|
$globals['active_ban_info'] = $this->usersCtx->tryGetActiveBan($this->authInfo->getUserInfo());
|
||||||
|
@ -278,17 +279,39 @@ class MisuzuContext {
|
||||||
$this->profileFields
|
$this->profileFields
|
||||||
));
|
));
|
||||||
|
|
||||||
$routingCtx->register(new \Misuzu\Hanyuu\HanyuuRoutes(
|
$routingCtx->register(new LegacyRoutes($this->urls));
|
||||||
$this->config->scopeTo('hanyuu'),
|
|
||||||
|
$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->config->scopeTo('impersonate'),
|
||||||
$this->urls,
|
$this->urls,
|
||||||
$this->usersCtx,
|
$this->usersCtx,
|
||||||
$this->authCtx,
|
$this->authCtx
|
||||||
$this->authInfo
|
|
||||||
));
|
));
|
||||||
|
|
||||||
$routingCtx->register(new LegacyRoutes($this->urls));
|
|
||||||
|
|
||||||
return $routingCtx;
|
return $routingCtx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use Index\DateTime;
|
use DateTimeInterface;
|
||||||
use Misuzu\MisuzuContext;
|
use Misuzu\MisuzuContext;
|
||||||
use Misuzu\Tools;
|
use Misuzu\Tools;
|
||||||
use Misuzu\Parsers\Parser;
|
use Misuzu\Parsers\Parser;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
use Twig\Extension\AbstractExtension;
|
use Twig\Extension\AbstractExtension;
|
||||||
use Twig\TwigFilter;
|
use Twig\TwigFilter;
|
||||||
use Twig\TwigFunction;
|
use Twig\TwigFunction;
|
||||||
|
@ -46,30 +47,18 @@ final class MisuzuSasaeExtension extends AbstractExtension {
|
||||||
return $this->assets?->{$name} ?? '';
|
return $this->assets?->{$name} ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function timeFormat(DateTime|string|int|null $dateTime): string {
|
public function timeFormat(DateTimeInterface|string|int|null $dateTime): string {
|
||||||
if($dateTime === null)
|
if($dateTime === null)
|
||||||
return 'never';
|
return 'never';
|
||||||
|
|
||||||
if(is_string($dateTime))
|
if(is_string($dateTime))
|
||||||
$dateTime = new DateTime($dateTime);
|
$dateTime = new CarbonImmutable($dateTime);
|
||||||
elseif(is_int($dateTime))
|
elseif(is_int($dateTime))
|
||||||
$dateTime = DateTime::fromUnixTimeSeconds($dateTime);
|
$dateTime = CarbonImmutable::createFromTimestampUTC($dateTime);
|
||||||
|
elseif(!($dateTime instanceof CarbonImmutable))
|
||||||
|
$dateTime = new CarbonImmutable($dateTime);
|
||||||
|
|
||||||
$string = '';
|
return $dateTime->diffForHumans();
|
||||||
$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 {
|
public function getHeaderMenu(): array {
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace Misuzu\News;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\DateTime;
|
use DateTimeInterface;
|
||||||
use Index\Data\DbStatementCache;
|
use Index\Data\DbStatementCache;
|
||||||
use Index\Data\IDbConnection;
|
use Index\Data\IDbConnection;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
@ -286,14 +286,14 @@ class News {
|
||||||
string $body,
|
string $body,
|
||||||
bool $featured = false,
|
bool $featured = false,
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
DateTime|int|null $schedule = null
|
DateTimeInterface|int|null $schedule = null
|
||||||
): NewsPostInfo {
|
): NewsPostInfo {
|
||||||
if($categoryInfo instanceof NewsCategoryInfo)
|
if($categoryInfo instanceof NewsCategoryInfo)
|
||||||
$categoryInfo = $categoryInfo->getId();
|
$categoryInfo = $categoryInfo->getId();
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
if($schedule instanceof DateTime)
|
if($schedule instanceof DateTimeInterface)
|
||||||
$schedule = $schedule->getUnixTimeSeconds();
|
$schedule = (int)$schedule->format('U');
|
||||||
|
|
||||||
$title = trim($title);
|
$title = trim($title);
|
||||||
if(empty($title))
|
if(empty($title))
|
||||||
|
@ -351,7 +351,7 @@ class News {
|
||||||
?bool $featured = null,
|
?bool $featured = null,
|
||||||
bool $updateUserInfo = false,
|
bool $updateUserInfo = false,
|
||||||
UserInfo|string|null $userInfo = null,
|
UserInfo|string|null $userInfo = null,
|
||||||
DateTime|int|null $schedule = null
|
DateTimeInterface|int|null $schedule = null
|
||||||
): void {
|
): void {
|
||||||
if($postInfo instanceof NewsPostInfo)
|
if($postInfo instanceof NewsPostInfo)
|
||||||
$postInfo = $postInfo->getId();
|
$postInfo = $postInfo->getId();
|
||||||
|
@ -359,8 +359,8 @@ class News {
|
||||||
$categoryInfo = $categoryInfo->getId();
|
$categoryInfo = $categoryInfo->getId();
|
||||||
if($userInfo instanceof UserInfo)
|
if($userInfo instanceof UserInfo)
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
if($schedule instanceof DateTime)
|
if($schedule instanceof DateTimeInterface)
|
||||||
$schedule = $schedule->getUnixTimeSeconds();
|
$schedule = (int)$schedule->format('U');
|
||||||
|
|
||||||
if($title !== null) {
|
if($title !== null) {
|
||||||
$title = trim($title);
|
$title = trim($title);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\News;
|
namespace Misuzu\News;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class NewsCategoryInfo {
|
class NewsCategoryInfo {
|
||||||
|
@ -45,8 +45,8 @@ class NewsCategoryInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPostsCount(): int {
|
public function getPostsCount(): int {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\News;
|
namespace Misuzu\News;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class NewsPostInfo {
|
class NewsPostInfo {
|
||||||
|
@ -84,8 +84,8 @@ class NewsPostInfo {
|
||||||
return $this->scheduled;
|
return $this->scheduled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getScheduledAt(): DateTime {
|
public function getScheduledAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->scheduled);
|
return CarbonImmutable::createFromTimestampUTC($this->scheduled);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isPublished(): bool {
|
public function isPublished(): bool {
|
||||||
|
@ -96,16 +96,16 @@ class NewsPostInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUpdatedTime(): int {
|
public function getUpdatedTime(): int {
|
||||||
return $this->updated;
|
return $this->updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUpdatedAt(): DateTime {
|
public function getUpdatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->updated);
|
return CarbonImmutable::createFromTimestampUTC($this->updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isEdited(): bool {
|
public function isEdited(): bool {
|
||||||
|
@ -120,7 +120,7 @@ class NewsPostInfo {
|
||||||
return $this->deleted;
|
return $this->deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDeletedAt(): ?DateTime {
|
public function getDeletedAt(): ?CarbonImmutable {
|
||||||
return $this->deleted === null ? null : DateTime::fromUnixTimeSeconds($this->deleted);
|
return $this->deleted === null ? null : CarbonImmutable::createFromTimestampUTC($this->deleted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
namespace Misuzu\News;
|
namespace Misuzu\News;
|
||||||
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\DateTime;
|
|
||||||
use Index\Data\{DbTools,IDbConnection};
|
use Index\Data\{DbTools,IDbConnection};
|
||||||
use Index\Http\Routing\{HttpGet,RouteHandler};
|
use Index\Http\Routing\{HttpGet,RouteHandler};
|
||||||
use Misuzu\{Pagination,SiteInfo,Template};
|
use Misuzu\{Pagination,SiteInfo,Template};
|
||||||
|
|
|
@ -4,8 +4,7 @@ namespace Misuzu\Perms;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\DateTime;
|
use Index\XDateTime;
|
||||||
use Index\Environment;
|
|
||||||
use Index\Data\DbStatementCache;
|
use Index\Data\DbStatementCache;
|
||||||
use Index\Data\DbTools;
|
use Index\Data\DbTools;
|
||||||
use Index\Data\IDbConnection;
|
use Index\Data\IDbConnection;
|
||||||
|
@ -371,10 +370,10 @@ class Permissions {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function precalculatePermissionsLog(string $fmt, ...$args): void {
|
private static function precalculatePermissionsLog(string $fmt, ...$args): void {
|
||||||
if(!Environment::isConsole())
|
if(!MSZ_CLI)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
echo DateTime::now()->format('[H:i:s.u] ');
|
echo XDateTime::now()->format('[H:i:s.u] ');
|
||||||
vprintf($fmt, $args);
|
vprintf($fmt, $args);
|
||||||
echo PHP_EOL;
|
echo PHP_EOL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
namespace Misuzu\SharpChat;
|
namespace Misuzu\SharpChat;
|
||||||
|
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\Colour\Colour;
|
|
||||||
use Index\Http\Routing\{HandlerAttribute,HttpDelete,HttpGet,HttpOptions,HttpPost,RouteHandler};
|
|
||||||
use Syokuhou\IConfig;
|
|
||||||
use Misuzu\RoutingContext;
|
use Misuzu\RoutingContext;
|
||||||
use Misuzu\Auth\{AuthContext,AuthInfo,Sessions};
|
use Misuzu\Auth\{AuthContext,AuthInfo,Sessions};
|
||||||
use Misuzu\Emoticons\Emotes;
|
use Misuzu\Emoticons\Emotes;
|
||||||
use Misuzu\Perms\Permissions;
|
use Misuzu\Perms\Permissions;
|
||||||
use Misuzu\URLs\URLRegistry;
|
use Misuzu\URLs\URLRegistry;
|
||||||
use Misuzu\Users\{Bans,UsersContext,UserInfo};
|
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 {
|
final class SharpChatRoutes extends RouteHandler {
|
||||||
private string $hashKey;
|
private string $hashKey;
|
||||||
|
@ -188,7 +188,50 @@ final class SharpChatRoutes extends RouteHandler {
|
||||||
if(!hash_equals($realHash, $userHash))
|
if(!hash_equals($realHash, $userHash))
|
||||||
return ['success' => false, 'reason' => 'hash'];
|
return ['success' => false, 'reason' => 'hash'];
|
||||||
|
|
||||||
if($authMethod === 'SESS' || $authMethod === 'Misuzu') {
|
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) {
|
||||||
$tokenPacker = $this->authCtx->createAuthTokenPacker();
|
$tokenPacker = $this->authCtx->createAuthTokenPacker();
|
||||||
$tokenInfo = $tokenPacker->unpack($authToken);
|
$tokenInfo = $tokenPacker->unpack($authToken);
|
||||||
if($tokenInfo->isEmpty()) {
|
if($tokenInfo->isEmpty()) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use Index\Serialisation\Base32;
|
use Index\Base32;
|
||||||
|
|
||||||
class TOTPGenerator {
|
class TOTPGenerator {
|
||||||
public const DIGITS = 6;
|
public const DIGITS = 6;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Users;
|
namespace Misuzu\Users;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class BanInfo {
|
class BanInfo {
|
||||||
|
@ -69,8 +69,8 @@ class BanInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isPermanent(): bool {
|
public function isPermanent(): bool {
|
||||||
|
@ -81,8 +81,8 @@ class BanInfo {
|
||||||
return $this->expires;
|
return $this->expires;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getExpiresAt(): ?DateTime {
|
public function getExpiresAt(): ?CarbonImmutable {
|
||||||
return $this->expires === null ? null : DateTime::fromUnixTimeSeconds($this->expires);
|
return $this->expires === null ? null : CarbonImmutable::createFromTimestampUTC($this->expires);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isActive(): bool {
|
public function isActive(): bool {
|
||||||
|
|
|
@ -3,11 +3,11 @@ namespace Misuzu\Users;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\DateTime;
|
use DateTimeInterface;
|
||||||
|
use Misuzu\Pagination;
|
||||||
use Index\Data\DbStatementCache;
|
use Index\Data\DbStatementCache;
|
||||||
use Index\Data\DbTools;
|
use Index\Data\DbTools;
|
||||||
use Index\Data\IDbConnection;
|
use Index\Data\IDbConnection;
|
||||||
use Misuzu\Pagination;
|
|
||||||
|
|
||||||
class Bans {
|
class Bans {
|
||||||
public const SEVERITY_MAX = 10;
|
public const SEVERITY_MAX = 10;
|
||||||
|
@ -152,7 +152,7 @@ class Bans {
|
||||||
|
|
||||||
public function createBan(
|
public function createBan(
|
||||||
UserInfo|string $userInfo,
|
UserInfo|string $userInfo,
|
||||||
DateTime|int|null $expires,
|
DateTimeInterface|int|null $expires,
|
||||||
string $publicReason,
|
string $publicReason,
|
||||||
string $privateReason,
|
string $privateReason,
|
||||||
int $severity = self::SEVERITY_DEFAULT,
|
int $severity = self::SEVERITY_DEFAULT,
|
||||||
|
@ -164,8 +164,8 @@ class Bans {
|
||||||
$userInfo = $userInfo->getId();
|
$userInfo = $userInfo->getId();
|
||||||
if($modInfo instanceof UserInfo)
|
if($modInfo instanceof UserInfo)
|
||||||
$modInfo = $modInfo->getId();
|
$modInfo = $modInfo->getId();
|
||||||
if($expires instanceof DateTime)
|
if($expires instanceof DateTimeInterface)
|
||||||
$expires = $expires->getUnixTimeSeconds();
|
$expires = (int)$expires->format('U');
|
||||||
|
|
||||||
$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 = $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);
|
$stmt->addParameter(1, $userInfo);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Users;
|
namespace Misuzu\Users;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class ModNoteInfo {
|
class ModNoteInfo {
|
||||||
|
@ -45,8 +45,8 @@ class ModNoteInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTitle(): string {
|
public function getTitle(): string {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
namespace Misuzu\Users;
|
namespace Misuzu\Users;
|
||||||
|
|
||||||
use Stringable;
|
use Stringable;
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Colour\Colour;
|
use Index\Colour\Colour;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
|
@ -89,8 +89,8 @@ class RoleInfo implements Stringable {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __toString(): string {
|
public function __toString(): string {
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu\Users;
|
namespace Misuzu\Users;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Misuzu\Parsers\Parser;
|
||||||
use Index\TimeZoneInfo;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Colour\Colour;
|
use Index\Colour\Colour;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
use Index\Net\IPAddress;
|
use Index\Net\IPAddress;
|
||||||
use Misuzu\Parsers\Parser;
|
|
||||||
|
|
||||||
class UserInfo {
|
class UserInfo {
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -131,8 +130,8 @@ class UserInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasLastActive(): bool {
|
public function hasLastActive(): bool {
|
||||||
|
@ -143,8 +142,8 @@ class UserInfo {
|
||||||
return $this->lastActive;
|
return $this->lastActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLastActiveAt(): ?DateTime {
|
public function getLastActiveAt(): ?CarbonImmutable {
|
||||||
return $this->lastActive === null ? null : DateTime::fromUnixTimeSeconds($this->lastActive);
|
return $this->lastActive === null ? null : CarbonImmutable::createFromTimestampUTC($this->lastActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isDeleted(): bool {
|
public function isDeleted(): bool {
|
||||||
|
@ -155,8 +154,8 @@ class UserInfo {
|
||||||
return $this->deleted;
|
return $this->deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDeletedAt(): ?DateTime {
|
public function getDeletedAt(): ?CarbonImmutable {
|
||||||
return $this->deleted === null ? null : DateTime::fromUnixTimeSeconds($this->deleted);
|
return $this->deleted === null ? null : CarbonImmutable::createFromTimestampUTC($this->deleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasDisplayRoleId(): bool {
|
public function hasDisplayRoleId(): bool {
|
||||||
|
@ -231,15 +230,15 @@ class UserInfo {
|
||||||
return $this->birthdate;
|
return $this->birthdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBirthdate(): ?DateTime {
|
public function getBirthdate(): ?CarbonImmutable {
|
||||||
return $this->birthdate === null ? null : DateTime::createFromFormat('Y-m-d', $this->birthdate, TimeZoneInfo::utc());
|
return $this->birthdate === null ? null : CarbonImmutable::createFromFormat('Y-m-d', $this->birthdate, 'UTC');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAge(): int {
|
public function getAge(): int {
|
||||||
$birthdate = $this->getBirthdate();
|
$birthdate = $this->getBirthdate();
|
||||||
if($birthdate === null || $birthdate->getYear() < 1900)
|
if($birthdate === null || (int)$birthdate->format('Y') < 1900)
|
||||||
return -1;
|
return -1;
|
||||||
return (int)$birthdate->diff(DateTime::now())->format('%y');
|
return (int)$birthdate->diff(CarbonImmutable::now())->format('%y');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasBackgroundSettings(): bool {
|
public function hasBackgroundSettings(): bool {
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace Misuzu\Users;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Index\DateTime;
|
use DateTimeInterface;
|
||||||
use Index\XString;
|
use Index\XString;
|
||||||
use Index\Colour\Colour;
|
use Index\Colour\Colour;
|
||||||
use Index\Data\DbStatementCache;
|
use Index\Data\DbStatementCache;
|
||||||
|
@ -46,7 +46,7 @@ class Users {
|
||||||
UserInfo|string|null $after = null,
|
UserInfo|string|null $after = null,
|
||||||
?int $lastActiveInMinutes = null,
|
?int $lastActiveInMinutes = null,
|
||||||
?int $newerThanDays = null,
|
?int $newerThanDays = null,
|
||||||
?DateTime $birthdate = null,
|
?DateTimeInterface $birthdate = null,
|
||||||
?bool $deleted = null
|
?bool $deleted = null
|
||||||
): int {
|
): int {
|
||||||
if($roleInfo instanceof RoleInfo)
|
if($roleInfo instanceof RoleInfo)
|
||||||
|
@ -106,7 +106,7 @@ class Users {
|
||||||
UserInfo|string|null $after = null,
|
UserInfo|string|null $after = null,
|
||||||
?int $lastActiveInMinutes = null,
|
?int $lastActiveInMinutes = null,
|
||||||
?int $newerThanDays = null,
|
?int $newerThanDays = null,
|
||||||
?DateTime $birthdate = null,
|
?DateTimeInterface $birthdate = null,
|
||||||
?bool $deleted = null,
|
?bool $deleted = null,
|
||||||
?string $orderBy = null,
|
?string $orderBy = null,
|
||||||
?bool $reverseOrder = null,
|
?bool $reverseOrder = null,
|
||||||
|
|
78
src/Users/UsersRpcActions.php
Normal file
78
src/Users/UsersRpcActions.php
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<?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\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();
|
||||||
|
|
||||||
|
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
|
<?php
|
||||||
namespace Misuzu\Users;
|
namespace Misuzu\Users;
|
||||||
|
|
||||||
use Index\DateTime;
|
use Carbon\CarbonImmutable;
|
||||||
use Index\Data\IDbResult;
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
class WarningInfo {
|
class WarningInfo {
|
||||||
|
@ -55,7 +55,7 @@ class WarningInfo {
|
||||||
return $this->created;
|
return $this->created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreatedAt(): DateTime {
|
public function getCreatedAt(): CarbonImmutable {
|
||||||
return DateTime::fromUnixTimeSeconds($this->created);
|
return CarbonImmutable::createFromTimestampUTC($this->created);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue