Compare commits

...

14 commits

72 changed files with 1200 additions and 1276 deletions

View file

@ -1,4 +1,4 @@
Copyright (c) 2017-2023, flashwave <me@flash.moe> Copyright (c) 2017-2024, flashwave <me@flash.moe>
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

266
composer.lock generated
View file

@ -8,16 +8,16 @@
"packages": [ "packages": [
{ {
"name": "chillerlan/php-qrcode", "name": "chillerlan/php-qrcode",
"version": "4.4.0", "version": "4.4.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/chillerlan/php-qrcode.git", "url": "https://github.com/chillerlan/php-qrcode.git",
"reference": "52889cd7ab1b78e6a345edafe24aa74bc5becc08" "reference": "f5e243f3b61a60934780579430a951460f40888d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/chillerlan/php-qrcode/zipball/52889cd7ab1b78e6a345edafe24aa74bc5becc08", "url": "https://api.github.com/repos/chillerlan/php-qrcode/zipball/f5e243f3b61a60934780579430a951460f40888d",
"reference": "52889cd7ab1b78e6a345edafe24aa74bc5becc08", "reference": "f5e243f3b61a60934780579430a951460f40888d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -27,10 +27,10 @@
}, },
"require-dev": { "require-dev": {
"phan/phan": "^5.4", "phan/phan": "^5.4",
"phpmd/phpmd": "^2.13", "phpmd/phpmd": "^2.15",
"phpunit/phpunit": "^9.6", "phpunit/phpunit": "^9.6",
"setasign/fpdf": "^1.8.2", "setasign/fpdf": "^1.8.2",
"squizlabs/php_codesniffer": "^3.7" "squizlabs/php_codesniffer": "^3.8"
}, },
"suggest": { "suggest": {
"chillerlan/php-authenticator": "Yet another Google authenticator! Also creates URIs for mobile apps.", "chillerlan/php-authenticator": "Yet another Google authenticator! Also creates URIs for mobile apps.",
@ -73,7 +73,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/chillerlan/php-qrcode/issues", "issues": "https://github.com/chillerlan/php-qrcode/issues",
"source": "https://github.com/chillerlan/php-qrcode/tree/4.4.0" "source": "https://github.com/chillerlan/php-qrcode/tree/4.4.1"
}, },
"funding": [ "funding": [
{ {
@ -85,20 +85,20 @@
"type": "ko_fi" "type": "ko_fi"
} }
], ],
"time": "2023-11-23T23:53:20+00:00" "time": "2024-01-06T16:56:58+00:00"
}, },
{ {
"name": "chillerlan/php-settings-container", "name": "chillerlan/php-settings-container",
"version": "3.1.0", "version": "3.2.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/chillerlan/php-settings-container.git", "url": "https://github.com/chillerlan/php-settings-container.git",
"reference": "4d02944424fa1f48abca96353257c93cbac856c1" "reference": "8f93648fac8e6bacac8e00a8d325eba4950295e6"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/4d02944424fa1f48abca96353257c93cbac856c1", "url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/8f93648fac8e6bacac8e00a8d325eba4950295e6",
"reference": "4d02944424fa1f48abca96353257c93cbac856c1", "reference": "8f93648fac8e6bacac8e00a8d325eba4950295e6",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -107,9 +107,9 @@
}, },
"require-dev": { "require-dev": {
"phan/phan": "^5.4", "phan/phan": "^5.4",
"phpmd/phpmd": "^2.13", "phpmd/phpmd": "^2.15",
"phpunit/phpunit": "^10.2", "phpunit/phpunit": "^10.5",
"squizlabs/php_codesniffer": "^3.7" "squizlabs/php_codesniffer": "^3.9"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -150,31 +150,31 @@
"type": "ko_fi" "type": "ko_fi"
} }
], ],
"time": "2023-07-17T20:46:37+00:00" "time": "2024-03-02T20:07:15+00:00"
}, },
{ {
"name": "doctrine/lexer", "name": "doctrine/lexer",
"version": "3.0.0", "version": "3.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/lexer.git", "url": "https://github.com/doctrine/lexer.git",
"reference": "84a527db05647743d50373e0ec53a152f2cde568" "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/84a527db05647743d50373e0ec53a152f2cde568", "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd",
"reference": "84a527db05647743d50373e0ec53a152f2cde568", "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^8.1" "php": "^8.1"
}, },
"require-dev": { "require-dev": {
"doctrine/coding-standard": "^10", "doctrine/coding-standard": "^12",
"phpstan/phpstan": "^1.9", "phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.5", "phpunit/phpunit": "^10.5",
"psalm/plugin-phpunit": "^0.18.3", "psalm/plugin-phpunit": "^0.18.3",
"vimeo/psalm": "^5.0" "vimeo/psalm": "^5.21"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -211,7 +211,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/lexer/issues", "issues": "https://github.com/doctrine/lexer/issues",
"source": "https://github.com/doctrine/lexer/tree/3.0.0" "source": "https://github.com/doctrine/lexer/tree/3.0.1"
}, },
"funding": [ "funding": [
{ {
@ -227,7 +227,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-12-15T16:57:16+00:00" "time": "2024-02-05T11:56:58+00:00"
}, },
{ {
"name": "egulias/email-validator", "name": "egulias/email-validator",
@ -352,7 +352,7 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://patchii.net/flash/index.git", "url": "https://patchii.net/flash/index.git",
"reference": "e31781c69f0b13fe251771c8e7e529222630a44f" "reference": "9d5b050b8928435416a7efbebe2a19ae8e626224"
}, },
"require": { "require": {
"ext-mbstring": "*", "ext-mbstring": "*",
@ -390,7 +390,7 @@
], ],
"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": "2023-11-20T19:01:19+00:00" "time": "2024-03-28T23:27:04+00:00"
}, },
{ {
"name": "flashwave/sasae", "name": "flashwave/sasae",
@ -398,7 +398,7 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://patchii.net/flash/sasae.git", "url": "https://patchii.net/flash/sasae.git",
"reference": "b56dd222acb8f138729e6258d4a90bbb8401ff52" "reference": "c8a9f2974e6591215b3f898dd5525de1e8367f66"
}, },
"require": { "require": {
"flashwave/index": "dev-master", "flashwave/index": "dev-master",
@ -431,7 +431,7 @@
], ],
"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": "2023-11-20T19:09:35+00:00" "time": "2024-01-04T02:13:42+00:00"
}, },
{ {
"name": "flashwave/syokuhou", "name": "flashwave/syokuhou",
@ -439,7 +439,7 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://patchii.net/flash/syokuhou.git", "url": "https://patchii.net/flash/syokuhou.git",
"reference": "fdf3c38cc216bf7024af331cbe1758532355c22f" "reference": "c1fe9371ada20fcea51c225cc53b9ceae4642bc4"
}, },
"require": { "require": {
"flashwave/index": "dev-master", "flashwave/index": "dev-master",
@ -470,7 +470,7 @@
], ],
"description": "Configuration library for PHP.", "description": "Configuration library for PHP.",
"homepage": "https://railgun.sh/syokuhou", "homepage": "https://railgun.sh/syokuhou",
"time": "2023-11-20T19:10:04+00:00" "time": "2024-01-04T02:12:49+00:00"
}, },
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
@ -590,16 +590,16 @@
}, },
{ {
"name": "jean85/pretty-package-versions", "name": "jean85/pretty-package-versions",
"version": "2.0.5", "version": "2.0.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Jean85/pretty-package-versions.git", "url": "https://github.com/Jean85/pretty-package-versions.git",
"reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af" "reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/ae547e455a3d8babd07b96966b17d7fd21d9c6af", "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/f9fdd29ad8e6d024f52678b570e5593759b550b4",
"reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af", "reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -607,9 +607,9 @@
"php": "^7.1|^8.0" "php": "^7.1|^8.0"
}, },
"require-dev": { "require-dev": {
"friendsofphp/php-cs-fixer": "^2.17", "friendsofphp/php-cs-fixer": "^3.2",
"jean85/composer-provided-replaced-stub-package": "^1.0", "jean85/composer-provided-replaced-stub-package": "^1.0",
"phpstan/phpstan": "^0.12.66", "phpstan/phpstan": "^1.4",
"phpunit/phpunit": "^7.5|^8.5|^9.4", "phpunit/phpunit": "^7.5|^8.5|^9.4",
"vimeo/psalm": "^4.3" "vimeo/psalm": "^4.3"
}, },
@ -643,22 +643,22 @@
], ],
"support": { "support": {
"issues": "https://github.com/Jean85/pretty-package-versions/issues", "issues": "https://github.com/Jean85/pretty-package-versions/issues",
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.5" "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.6"
}, },
"time": "2021-10-08T21:21:46+00:00" "time": "2024-03-08T09:58:59+00:00"
}, },
{ {
"name": "matomo/device-detector", "name": "matomo/device-detector",
"version": "6.2.0", "version": "6.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/matomo-org/device-detector.git", "url": "https://github.com/matomo-org/device-detector.git",
"reference": "3577abbfea71eaf88d4cd432274428c39601754f" "reference": "35efad75b31f2596701834d19f097497909572a4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/3577abbfea71eaf88d4cd432274428c39601754f", "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/35efad75b31f2596701834d19f097497909572a4",
"reference": "3577abbfea71eaf88d4cd432274428c39601754f", "reference": "35efad75b31f2596701834d19f097497909572a4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -670,8 +670,8 @@
}, },
"require-dev": { "require-dev": {
"matthiasmullie/scrapbook": "^1.4.7", "matthiasmullie/scrapbook": "^1.4.7",
"mayflower/mo4-coding-standard": "^v8.0.0", "mayflower/mo4-coding-standard": "^v9.0.0",
"phpstan/phpstan": "^0.12.52", "phpstan/phpstan": "^1.10.44",
"phpunit/phpunit": "^8.5.8", "phpunit/phpunit": "^8.5.8",
"psr/cache": "^1.0.1", "psr/cache": "^1.0.1",
"psr/simple-cache": "^1.0.1", "psr/simple-cache": "^1.0.1",
@ -714,14 +714,14 @@
"source": "https://github.com/matomo-org/matomo", "source": "https://github.com/matomo-org/matomo",
"wiki": "https://dev.matomo.org/" "wiki": "https://dev.matomo.org/"
}, },
"time": "2023-11-15T09:44:42+00:00" "time": "2024-02-16T16:26:57+00:00"
}, },
{ {
"name": "mustangostang/spyc", "name": "mustangostang/spyc",
"version": "0.6.3", "version": "0.6.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "git@github.com:mustangostang/spyc.git", "url": "https://github.com/mustangostang/spyc.git",
"reference": "4627c838b16550b666d15aeae1e5289dd5b77da0" "reference": "4627c838b16550b666d15aeae1e5289dd5b77da0"
}, },
"dist": { "dist": {
@ -764,6 +764,10 @@
"yaml", "yaml",
"yml" "yml"
], ],
"support": {
"issues": "https://github.com/mustangostang/spyc/issues",
"source": "https://github.com/mustangostang/spyc/tree/0.6.3"
},
"time": "2019-09-10T13:16:29+00:00" "time": "2019-09-10T13:16:29+00:00"
}, },
{ {
@ -1128,16 +1132,16 @@
}, },
{ {
"name": "sentry/sentry", "name": "sentry/sentry",
"version": "4.1.0", "version": "4.6.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/getsentry/sentry-php.git", "url": "https://github.com/getsentry/sentry-php.git",
"reference": "89666f297891ff937fceb2f3d1fb967a6848cf37" "reference": "5a94184175e5830b589bf923da8c9c3af2c0f409"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/89666f297891ff937fceb2f3d1fb967a6848cf37", "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/5a94184175e5830b589bf923da8c9c3af2c0f409",
"reference": "89666f297891ff937fceb2f3d1fb967a6848cf37", "reference": "5a94184175e5830b589bf923da8c9c3af2c0f409",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1161,7 +1165,7 @@
"phpbench/phpbench": "^1.0", "phpbench/phpbench": "^1.0",
"phpstan/phpstan": "^1.3", "phpstan/phpstan": "^1.3",
"phpunit/phpunit": "^8.5.14|^9.4", "phpunit/phpunit": "^8.5.14|^9.4",
"symfony/phpunit-bridge": "^5.2|^6.0", "symfony/phpunit-bridge": "^5.2|^6.0|^7.0",
"vimeo/psalm": "^4.17" "vimeo/psalm": "^4.17"
}, },
"suggest": { "suggest": {
@ -1201,7 +1205,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/getsentry/sentry-php/issues", "issues": "https://github.com/getsentry/sentry-php/issues",
"source": "https://github.com/getsentry/sentry-php/tree/4.1.0" "source": "https://github.com/getsentry/sentry-php/tree/4.6.1"
}, },
"funding": [ "funding": [
{ {
@ -1213,7 +1217,7 @@
"type": "custom" "type": "custom"
} }
], ],
"time": "2023-12-04T12:41:21+00:00" "time": "2024-03-08T08:18:09+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
@ -1284,16 +1288,16 @@
}, },
{ {
"name": "symfony/event-dispatcher", "name": "symfony/event-dispatcher",
"version": "v7.0.0", "version": "v7.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/event-dispatcher.git", "url": "https://github.com/symfony/event-dispatcher.git",
"reference": "c459b40ffe67c49af6fd392aac374c9edf8a027e" "reference": "834c28d533dd0636f910909d01b9ff45cc094b5e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c459b40ffe67c49af6fd392aac374c9edf8a027e", "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/834c28d533dd0636f910909d01b9ff45cc094b5e",
"reference": "c459b40ffe67c49af6fd392aac374c9edf8a027e", "reference": "834c28d533dd0636f910909d01b9ff45cc094b5e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1344,7 +1348,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v7.0.0" "source": "https://github.com/symfony/event-dispatcher/tree/v7.0.3"
}, },
"funding": [ "funding": [
{ {
@ -1360,7 +1364,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-07-27T16:29:09+00:00" "time": "2024-01-23T15:02:46+00:00"
}, },
{ {
"name": "symfony/event-dispatcher-contracts", "name": "symfony/event-dispatcher-contracts",
@ -1440,16 +1444,16 @@
}, },
{ {
"name": "symfony/mailer", "name": "symfony/mailer",
"version": "v6.4.0", "version": "v6.4.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/mailer.git", "url": "https://github.com/symfony/mailer.git",
"reference": "ca8dcf8892cdc5b4358ecf2528429bb5e706f7ba" "reference": "791c5d31a8204cf3db0c66faab70282307f4376b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/mailer/zipball/ca8dcf8892cdc5b4358ecf2528429bb5e706f7ba", "url": "https://api.github.com/repos/symfony/mailer/zipball/791c5d31a8204cf3db0c66faab70282307f4376b",
"reference": "ca8dcf8892cdc5b4358ecf2528429bb5e706f7ba", "reference": "791c5d31a8204cf3db0c66faab70282307f4376b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1500,7 +1504,7 @@
"description": "Helps sending emails", "description": "Helps sending emails",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/mailer/tree/v6.4.0" "source": "https://github.com/symfony/mailer/tree/v6.4.4"
}, },
"funding": [ "funding": [
{ {
@ -1516,20 +1520,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-11-12T18:02:22+00:00" "time": "2024-02-03T21:33:47+00:00"
}, },
{ {
"name": "symfony/mime", "name": "symfony/mime",
"version": "v7.0.0", "version": "v7.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/mime.git", "url": "https://github.com/symfony/mime.git",
"reference": "0a2fff95c1a10df97f571d67e76c7ae0f0d4f535" "reference": "c1ffe24ba6fdc3e3f0f3fcb93519103b326a3716"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/0a2fff95c1a10df97f571d67e76c7ae0f0d4f535", "url": "https://api.github.com/repos/symfony/mime/zipball/c1ffe24ba6fdc3e3f0f3fcb93519103b326a3716",
"reference": "0a2fff95c1a10df97f571d67e76c7ae0f0d4f535", "reference": "c1ffe24ba6fdc3e3f0f3fcb93519103b326a3716",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1583,7 +1587,7 @@
"mime-type" "mime-type"
], ],
"support": { "support": {
"source": "https://github.com/symfony/mime/tree/v7.0.0" "source": "https://github.com/symfony/mime/tree/v7.0.3"
}, },
"funding": [ "funding": [
{ {
@ -1599,7 +1603,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-10-19T14:20:43+00:00" "time": "2024-01-30T08:34:29+00:00"
}, },
{ {
"name": "symfony/options-resolver", "name": "symfony/options-resolver",
@ -1670,16 +1674,16 @@
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
"version": "v1.28.0", "version": "v1.29.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git", "url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1693,9 +1697,6 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill" "url": "https://github.com/symfony/polyfill"
@ -1732,7 +1733,7 @@
"portable" "portable"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
}, },
"funding": [ "funding": [
{ {
@ -1748,20 +1749,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-01-26T09:26:14+00:00" "time": "2024-01-29T20:11:03+00:00"
}, },
{ {
"name": "symfony/polyfill-intl-idn", "name": "symfony/polyfill-intl-idn",
"version": "v1.28.0", "version": "v1.29.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git", "url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "ecaafce9f77234a6a449d29e49267ba10499116d" "reference": "a287ed7475f85bf6f61890146edbc932c0fff919"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/ecaafce9f77234a6a449d29e49267ba10499116d", "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a287ed7475f85bf6f61890146edbc932c0fff919",
"reference": "ecaafce9f77234a6a449d29e49267ba10499116d", "reference": "a287ed7475f85bf6f61890146edbc932c0fff919",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1774,9 +1775,6 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill" "url": "https://github.com/symfony/polyfill"
@ -1819,7 +1817,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.28.0" "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.29.0"
}, },
"funding": [ "funding": [
{ {
@ -1835,20 +1833,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-01-26T09:30:37+00:00" "time": "2024-01-29T20:11:03+00:00"
}, },
{ {
"name": "symfony/polyfill-intl-normalizer", "name": "symfony/polyfill-intl-normalizer",
"version": "v1.28.0", "version": "v1.29.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" "reference": "bc45c394692b948b4d383a08d7753968bed9a83d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d",
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", "reference": "bc45c394692b948b4d383a08d7753968bed9a83d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1859,9 +1857,6 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill" "url": "https://github.com/symfony/polyfill"
@ -1903,7 +1898,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0"
}, },
"funding": [ "funding": [
{ {
@ -1919,20 +1914,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-01-26T09:26:14+00:00" "time": "2024-01-29T20:11:03+00:00"
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
"version": "v1.28.0", "version": "v1.29.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git", "url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "42292d99c55abe617799667f454222c54c60e229" "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
"reference": "42292d99c55abe617799667f454222c54c60e229", "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1946,9 +1941,6 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill" "url": "https://github.com/symfony/polyfill"
@ -1986,7 +1978,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
}, },
"funding": [ "funding": [
{ {
@ -2002,20 +1994,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-07-28T09:04:16+00:00" "time": "2024-01-29T20:11:03+00:00"
}, },
{ {
"name": "symfony/polyfill-php72", "name": "symfony/polyfill-php72",
"version": "v1.28.0", "version": "v1.29.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php72.git", "url": "https://github.com/symfony/polyfill-php72.git",
"reference": "70f4aebd92afca2f865444d30a4d2151c13c3179" "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/70f4aebd92afca2f865444d30a4d2151c13c3179", "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25",
"reference": "70f4aebd92afca2f865444d30a4d2151c13c3179", "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2023,9 +2015,6 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill" "url": "https://github.com/symfony/polyfill"
@ -2062,7 +2051,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php72/tree/v1.28.0" "source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0"
}, },
"funding": [ "funding": [
{ {
@ -2078,20 +2067,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-01-26T09:26:14+00:00" "time": "2024-01-29T20:11:03+00:00"
}, },
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
"version": "v1.28.0", "version": "v1.29.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php80.git", "url": "https://github.com/symfony/polyfill-php80.git",
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2099,9 +2088,6 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill" "url": "https://github.com/symfony/polyfill"
@ -2145,7 +2131,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
}, },
"funding": [ "funding": [
{ {
@ -2161,25 +2147,25 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-01-26T09:26:14+00:00" "time": "2024-01-29T20:11:03+00:00"
}, },
{ {
"name": "symfony/service-contracts", "name": "symfony/service-contracts",
"version": "v3.4.0", "version": "v3.4.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/service-contracts.git", "url": "https://github.com/symfony/service-contracts.git",
"reference": "b3313c2dbffaf71c8de2934e2ea56ed2291a3838" "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/b3313c2dbffaf71c8de2934e2ea56ed2291a3838", "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0",
"reference": "b3313c2dbffaf71c8de2934e2ea56ed2291a3838", "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.1", "php": ">=8.1",
"psr/container": "^2.0" "psr/container": "^1.1|^2.0"
}, },
"conflict": { "conflict": {
"ext-psr": "<1.1|>=2" "ext-psr": "<1.1|>=2"
@ -2227,7 +2213,7 @@
"standards" "standards"
], ],
"support": { "support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.4.0" "source": "https://github.com/symfony/service-contracts/tree/v3.4.1"
}, },
"funding": [ "funding": [
{ {
@ -2243,7 +2229,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-07-30T20:28:31+00:00" "time": "2023-12-26T14:02:43+00:00"
}, },
{ {
"name": "twig/html-extra", "name": "twig/html-extra",
@ -2385,16 +2371,16 @@
"packages-dev": [ "packages-dev": [
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.10.50", "version": "1.10.66",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "06a98513ac72c03e8366b5a0cb00750b487032e4" "reference": "94779c987e4ebd620025d9e5fdd23323903950bd"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/06a98513ac72c03e8366b5a0cb00750b487032e4", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/94779c987e4ebd620025d9e5fdd23323903950bd",
"reference": "06a98513ac72c03e8366b5a0cb00750b487032e4", "reference": "94779c987e4ebd620025d9e5fdd23323903950bd",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2443,7 +2429,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-12-13T10:59:42+00:00" "time": "2024-03-28T16:17:31+00:00"
} }
], ],
"aliases": [], "aliases": [],
@ -2457,5 +2443,5 @@
"prefer-lowest": false, "prefer-lowest": false,
"platform": [], "platform": [],
"platform-dev": [], "platform-dev": [],
"plugin-api-version": "2.3.0" "plugin-api-version": "2.6.0"
} }

461
package-lock.json generated
View file

@ -5,19 +5,19 @@
"packages": { "packages": {
"": { "": {
"dependencies": { "dependencies": {
"@swc/core": "^1.3.69", "@swc/core": "^1.4.11",
"autoprefixer": "^10.4.14", "autoprefixer": "^10.4.19",
"cssnano": "^6.0.1", "cssnano": "^6.1.2",
"postcss": "^8.4.26" "postcss": "^8.4.38"
} }
}, },
"node_modules/@swc/core": { "node_modules/@swc/core": {
"version": "1.3.105", "version": "1.4.11",
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.105.tgz", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.4.11.tgz",
"integrity": "sha512-me2VZyr3OjqRpFrYQJJYy7x/zbFSl9nt+MAGnIcBtjDsN00iTVqEaKxBjPBFQV9BDAgPz2SRWes/DhhVm5SmMw==", "integrity": "sha512-WKEakMZxkVwRdgMN4AMJ9K5nysY8g8npgQPczmjBeNK5In7QEAZAJwnyccrWwJZU0XjVeHn2uj+XbOKdDW17rg==",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@swc/counter": "^0.1.1", "@swc/counter": "^0.1.2",
"@swc/types": "^0.1.5" "@swc/types": "^0.1.5"
}, },
"engines": { "engines": {
@ -28,16 +28,16 @@
"url": "https://opencollective.com/swc" "url": "https://opencollective.com/swc"
}, },
"optionalDependencies": { "optionalDependencies": {
"@swc/core-darwin-arm64": "1.3.105", "@swc/core-darwin-arm64": "1.4.11",
"@swc/core-darwin-x64": "1.3.105", "@swc/core-darwin-x64": "1.4.11",
"@swc/core-linux-arm-gnueabihf": "1.3.105", "@swc/core-linux-arm-gnueabihf": "1.4.11",
"@swc/core-linux-arm64-gnu": "1.3.105", "@swc/core-linux-arm64-gnu": "1.4.11",
"@swc/core-linux-arm64-musl": "1.3.105", "@swc/core-linux-arm64-musl": "1.4.11",
"@swc/core-linux-x64-gnu": "1.3.105", "@swc/core-linux-x64-gnu": "1.4.11",
"@swc/core-linux-x64-musl": "1.3.105", "@swc/core-linux-x64-musl": "1.4.11",
"@swc/core-win32-arm64-msvc": "1.3.105", "@swc/core-win32-arm64-msvc": "1.4.11",
"@swc/core-win32-ia32-msvc": "1.3.105", "@swc/core-win32-ia32-msvc": "1.4.11",
"@swc/core-win32-x64-msvc": "1.3.105" "@swc/core-win32-x64-msvc": "1.4.11"
}, },
"peerDependencies": { "peerDependencies": {
"@swc/helpers": "^0.5.0" "@swc/helpers": "^0.5.0"
@ -49,9 +49,9 @@
} }
}, },
"node_modules/@swc/core-darwin-arm64": { "node_modules/@swc/core-darwin-arm64": {
"version": "1.3.105", "version": "1.4.11",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.105.tgz", "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.11.tgz",
"integrity": "sha512-buWeweLVDXXmcnfIemH4PGnpjwsDTUGitnPchdftb0u1FU8zSSP/lw/pUCBDG/XvWAp7c/aFxgN4CyG0j7eayA==", "integrity": "sha512-C1j1Qp/IHSelVWdEnT7f0iONWxQz6FAqzjCF2iaL+0vFg4V5f2nlgrueY8vj5pNNzSGhrAlxsMxEIp4dj1MXkg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -64,9 +64,9 @@
} }
}, },
"node_modules/@swc/core-darwin-x64": { "node_modules/@swc/core-darwin-x64": {
"version": "1.3.105", "version": "1.4.11",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.105.tgz", "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.4.11.tgz",
"integrity": "sha512-hFmXPApqjA/8sy/9NpljHVaKi1OvL9QkJ2MbbTCCbJERuHMpMUeMBUWipHRfepGHFhU+9B9zkEup/qJaJR4XIg==", "integrity": "sha512-0TTy3Ni8ncgaMCchSQ7FK8ZXQLlamy0FXmGWbR58c+pVZWYZltYPTmheJUvVcR0H2+gPAymRKyfC0iLszDALjg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -79,9 +79,9 @@
} }
}, },
"node_modules/@swc/core-linux-arm-gnueabihf": { "node_modules/@swc/core-linux-arm-gnueabihf": {
"version": "1.3.105", "version": "1.4.11",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.105.tgz", "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.11.tgz",
"integrity": "sha512-mwXyMC41oMKkKrPpL8uJpOxw7fyfQoVtIw3Y5p0Blabk+espNYqix0E8VymHdRKuLmM//z5wVmMsuHdGBHvZeg==", "integrity": "sha512-XJLB71uw0rog4DjYAPxFGAuGCBQpgJDlPZZK6MTmZOvI/1t0+DelJ24IjHIxk500YYM26Yv47xPabqFPD7I2zQ==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -94,9 +94,9 @@
} }
}, },
"node_modules/@swc/core-linux-arm64-gnu": { "node_modules/@swc/core-linux-arm64-gnu": {
"version": "1.3.105", "version": "1.4.11",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.105.tgz", "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.11.tgz",
"integrity": "sha512-H7yEIVydnUtqBSUxwmO6vpIQn7j+Rr0DF6ZOORPyd/SFzQJK9cJRtmJQ3ZMzlJ1Bb+1gr3MvjgLEnmyCYEm2Hg==", "integrity": "sha512-vYQwzJvm/iu052d5Iw27UFALIN5xSrGkPZXxLNMHPySVko2QMNNBv35HLatkEQHbQ3X+VKSW9J9SkdtAvAVRAQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -109,9 +109,9 @@
} }
}, },
"node_modules/@swc/core-linux-arm64-musl": { "node_modules/@swc/core-linux-arm64-musl": {
"version": "1.3.105", "version": "1.4.11",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.105.tgz", "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.11.tgz",
"integrity": "sha512-Jg7RTFT3pGFdGt5elPV6oDkinRy7q9cXpenjXnJnM2uvx3jOwnsAhexPyCDHom8SHL0j+9kaLLC66T3Gz1E4UA==", "integrity": "sha512-eV+KduiRYUFjPsvbZuJ9aknQH9Tj0U2/G9oIZSzLx/18WsYi+upzHbgxmIIHJ2VJgfd7nN40RI/hMtxNsUzR/g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -124,9 +124,9 @@
} }
}, },
"node_modules/@swc/core-linux-x64-gnu": { "node_modules/@swc/core-linux-x64-gnu": {
"version": "1.3.105", "version": "1.4.11",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.105.tgz", "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.11.tgz",
"integrity": "sha512-DJghplpyusAmp1X5pW/y93MmS/u83Sx5GrpJxI6KLPa82+NItTgMcl8KBQmW5GYAJpVKZyaIvBanS5TdR8aN2w==", "integrity": "sha512-WA1iGXZ2HpqM1OR9VCQZJ8sQ1KP2or9O4bO8vWZo6HZJIeoQSo7aa9waaCLRpkZvkng1ct/TF/l6ymqSNFXIzQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -139,9 +139,9 @@
} }
}, },
"node_modules/@swc/core-linux-x64-musl": { "node_modules/@swc/core-linux-x64-musl": {
"version": "1.3.105", "version": "1.4.11",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.105.tgz", "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.11.tgz",
"integrity": "sha512-wD5jL2dZH/5nPNssBo6jhOvkI0lmWnVR4vnOXWjuXgjq1S0AJpO5jdre/6pYLmf26hft3M42bteDnjR4AAZ38w==", "integrity": "sha512-UkVJToKf0owwQYRnGvjHAeYVDfeimCEcx0VQSbJoN7Iy0ckRZi7YPlmWJU31xtKvikE2bQWCOVe0qbSDqqcWXA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -154,9 +154,9 @@
} }
}, },
"node_modules/@swc/core-win32-arm64-msvc": { "node_modules/@swc/core-win32-arm64-msvc": {
"version": "1.3.105", "version": "1.4.11",
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.105.tgz", "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.11.tgz",
"integrity": "sha512-UqJtwILUHRw2+3UTPnRkZrzM/bGdQtbR4UFdp79mZQYfryeOUVNg7aJj/bWUTkKtLiZ3o+FBNrM/x2X1mJX5bA==", "integrity": "sha512-35khwkyly7lF5NDSyvIrukBMzxPorgc5iTSDfVO/LvnmN5+fm4lTlrDr4tUfTdOhv3Emy7CsKlsNAeFRJ+Pm+w==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -169,9 +169,9 @@
} }
}, },
"node_modules/@swc/core-win32-ia32-msvc": { "node_modules/@swc/core-win32-ia32-msvc": {
"version": "1.3.105", "version": "1.4.11",
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.105.tgz", "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.11.tgz",
"integrity": "sha512-Z95C6vZgBEJ1snidYyjVKnVWiy/ZpPiIFIXGWkDr4ZyBgL3eZX12M6LzZ+NApHKffrbO4enbFyFomueBQgS2oA==", "integrity": "sha512-Wx8/6f0ufgQF2pbVPsJ2dAmFLwIOW+xBE5fxnb7VnEbGkTgP1qMDWiiAtD9rtvDSuODG3i1AEmAak/2HAc6i6A==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -184,9 +184,9 @@
} }
}, },
"node_modules/@swc/core-win32-x64-msvc": { "node_modules/@swc/core-win32-x64-msvc": {
"version": "1.3.105", "version": "1.4.11",
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.105.tgz", "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.11.tgz",
"integrity": "sha512-3J8fkyDPFsS3mszuYUY4Wfk7/B2oio9qXUwF3DzOs2MK+XgdyMLIptIxL7gdfitXJBH8k39uVjrIw1JGJDjyFA==", "integrity": "sha512-0xRFW6K9UZQH2NVC/0pVB0GJXS45lY24f+6XaPBF1YnMHd8A8GoHl7ugyM5yNUTe2AKhSgk5fJV00EJt/XBtdQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -199,14 +199,17 @@
} }
}, },
"node_modules/@swc/counter": { "node_modules/@swc/counter": {
"version": "0.1.2", "version": "0.1.3",
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
"integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==" "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="
}, },
"node_modules/@swc/types": { "node_modules/@swc/types": {
"version": "0.1.5", "version": "0.1.6",
"resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.6.tgz",
"integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==" "integrity": "sha512-/JLo/l2JsT/LRd80C3HfbmVpxOAJ11FO2RCEslFrgzLltoP9j8XIbsyDcfCt2WWyX+CM96rBoNM+IToAkFOugg==",
"dependencies": {
"@swc/counter": "^0.1.3"
}
}, },
"node_modules/@trysound/sax": { "node_modules/@trysound/sax": {
"version": "0.2.0", "version": "0.2.0",
@ -217,9 +220,9 @@
} }
}, },
"node_modules/autoprefixer": { "node_modules/autoprefixer": {
"version": "10.4.17", "version": "10.4.19",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz",
"integrity": "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==", "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -235,8 +238,8 @@
} }
], ],
"dependencies": { "dependencies": {
"browserslist": "^4.22.2", "browserslist": "^4.23.0",
"caniuse-lite": "^1.0.30001578", "caniuse-lite": "^1.0.30001599",
"fraction.js": "^4.3.7", "fraction.js": "^4.3.7",
"normalize-range": "^0.1.2", "normalize-range": "^0.1.2",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
@ -258,9 +261,9 @@
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
}, },
"node_modules/browserslist": { "node_modules/browserslist": {
"version": "4.22.2", "version": "4.23.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
"integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -276,8 +279,8 @@
} }
], ],
"dependencies": { "dependencies": {
"caniuse-lite": "^1.0.30001565", "caniuse-lite": "^1.0.30001587",
"electron-to-chromium": "^1.4.601", "electron-to-chromium": "^1.4.668",
"node-releases": "^2.0.14", "node-releases": "^2.0.14",
"update-browserslist-db": "^1.0.13" "update-browserslist-db": "^1.0.13"
}, },
@ -300,9 +303,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001579", "version": "1.0.30001600",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz",
"integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==", "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -332,9 +335,9 @@
} }
}, },
"node_modules/css-declaration-sorter": { "node_modules/css-declaration-sorter": {
"version": "7.1.1", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.1.1.tgz", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz",
"integrity": "sha512-dZ3bVTEEc1vxr3Bek9vGwfB5Z6ESPULhcRvO472mfjVnj8jRcTnKO8/JTczlvxM10Myb+wBM++1MtdO76eWcaQ==", "integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==",
"engines": { "engines": {
"node": "^14 || ^16 || >=18" "node": "^14 || ^16 || >=18"
}, },
@ -392,12 +395,12 @@
} }
}, },
"node_modules/cssnano": { "node_modules/cssnano": {
"version": "6.0.3", "version": "6.1.2",
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.3.tgz", "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz",
"integrity": "sha512-MRq4CIj8pnyZpcI2qs6wswoYoDD1t0aL28n+41c1Ukcpm56m1h6mCexIHBGjfZfnTqtGSSCP4/fB1ovxgjBOiw==", "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==",
"dependencies": { "dependencies": {
"cssnano-preset-default": "^6.0.3", "cssnano-preset-default": "^6.1.2",
"lilconfig": "^3.0.0" "lilconfig": "^3.1.1"
}, },
"engines": { "engines": {
"node": "^14 || ^16 || >=18.0" "node": "^14 || ^16 || >=18.0"
@ -411,39 +414,40 @@
} }
}, },
"node_modules/cssnano-preset-default": { "node_modules/cssnano-preset-default": {
"version": "6.0.3", "version": "6.1.2",
"resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.3.tgz", "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz",
"integrity": "sha512-4y3H370aZCkT9Ev8P4SO4bZbt+AExeKhh8wTbms/X7OLDo5E7AYUUy6YPxa/uF5Grf+AJwNcCnxKhZynJ6luBA==", "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==",
"dependencies": { "dependencies": {
"css-declaration-sorter": "^7.1.1", "browserslist": "^4.23.0",
"cssnano-utils": "^4.0.1", "css-declaration-sorter": "^7.2.0",
"cssnano-utils": "^4.0.2",
"postcss-calc": "^9.0.1", "postcss-calc": "^9.0.1",
"postcss-colormin": "^6.0.2", "postcss-colormin": "^6.1.0",
"postcss-convert-values": "^6.0.2", "postcss-convert-values": "^6.1.0",
"postcss-discard-comments": "^6.0.1", "postcss-discard-comments": "^6.0.2",
"postcss-discard-duplicates": "^6.0.1", "postcss-discard-duplicates": "^6.0.3",
"postcss-discard-empty": "^6.0.1", "postcss-discard-empty": "^6.0.3",
"postcss-discard-overridden": "^6.0.1", "postcss-discard-overridden": "^6.0.2",
"postcss-merge-longhand": "^6.0.2", "postcss-merge-longhand": "^6.0.5",
"postcss-merge-rules": "^6.0.3", "postcss-merge-rules": "^6.1.1",
"postcss-minify-font-values": "^6.0.1", "postcss-minify-font-values": "^6.1.0",
"postcss-minify-gradients": "^6.0.1", "postcss-minify-gradients": "^6.0.3",
"postcss-minify-params": "^6.0.2", "postcss-minify-params": "^6.1.0",
"postcss-minify-selectors": "^6.0.2", "postcss-minify-selectors": "^6.0.4",
"postcss-normalize-charset": "^6.0.1", "postcss-normalize-charset": "^6.0.2",
"postcss-normalize-display-values": "^6.0.1", "postcss-normalize-display-values": "^6.0.2",
"postcss-normalize-positions": "^6.0.1", "postcss-normalize-positions": "^6.0.2",
"postcss-normalize-repeat-style": "^6.0.1", "postcss-normalize-repeat-style": "^6.0.2",
"postcss-normalize-string": "^6.0.1", "postcss-normalize-string": "^6.0.2",
"postcss-normalize-timing-functions": "^6.0.1", "postcss-normalize-timing-functions": "^6.0.2",
"postcss-normalize-unicode": "^6.0.2", "postcss-normalize-unicode": "^6.1.0",
"postcss-normalize-url": "^6.0.1", "postcss-normalize-url": "^6.0.2",
"postcss-normalize-whitespace": "^6.0.1", "postcss-normalize-whitespace": "^6.0.2",
"postcss-ordered-values": "^6.0.1", "postcss-ordered-values": "^6.0.2",
"postcss-reduce-initial": "^6.0.2", "postcss-reduce-initial": "^6.1.0",
"postcss-reduce-transforms": "^6.0.1", "postcss-reduce-transforms": "^6.0.2",
"postcss-svgo": "^6.0.2", "postcss-svgo": "^6.0.3",
"postcss-unique-selectors": "^6.0.2" "postcss-unique-selectors": "^6.0.4"
}, },
"engines": { "engines": {
"node": "^14 || ^16 || >=18.0" "node": "^14 || ^16 || >=18.0"
@ -453,9 +457,9 @@
} }
}, },
"node_modules/cssnano-utils": { "node_modules/cssnano-utils": {
"version": "4.0.1", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.1.tgz", "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz",
"integrity": "sha512-6qQuYDqsGoiXssZ3zct6dcMxiqfT6epy7x4R0TQJadd4LWO3sPR6JH6ZByOvVLoZ6EdwPGgd7+DR1EmX3tiXQQ==", "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==",
"engines": { "engines": {
"node": "^14 || ^16 || >=18.0" "node": "^14 || ^16 || >=18.0"
}, },
@ -545,9 +549,9 @@
} }
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.4.643", "version": "1.4.722",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.643.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.722.tgz",
"integrity": "sha512-QHscvvS7gt155PtoRC0dR2ilhL8E9LHhfTQEq1uD5AL0524rBLAwpAREFH06f87/e45B9XkR6Ki5dbhbCsVEIg==" "integrity": "sha512-5nLE0TWFFpZ80Crhtp4pIp8LXCztjYX41yUcV6b+bKR2PqzjskTMOOlBi1VjBHlvHwS+4gar7kNKOrsbsewEZQ=="
}, },
"node_modules/entities": { "node_modules/entities": {
"version": "4.5.0", "version": "4.5.0",
@ -561,9 +565,9 @@
} }
}, },
"node_modules/escalade": { "node_modules/escalade": {
"version": "3.1.1", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
@ -581,11 +585,14 @@
} }
}, },
"node_modules/lilconfig": { "node_modules/lilconfig": {
"version": "3.0.0", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz",
"integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==",
"engines": { "engines": {
"node": ">=14" "node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antonk52"
} }
}, },
"node_modules/lodash.memoize": { "node_modules/lodash.memoize": {
@ -650,9 +657,9 @@
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.33", "version": "8.4.38",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
"integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -670,7 +677,7 @@
"dependencies": { "dependencies": {
"nanoid": "^3.3.7", "nanoid": "^3.3.7",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
"source-map-js": "^1.0.2" "source-map-js": "^1.2.0"
}, },
"engines": { "engines": {
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
@ -692,13 +699,13 @@
} }
}, },
"node_modules/postcss-colormin": { "node_modules/postcss-colormin": {
"version": "6.0.2", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.2.tgz", "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz",
"integrity": "sha512-TXKOxs9LWcdYo5cgmcSHPkyrLAh86hX1ijmyy6J8SbOhyv6ua053M3ZAM/0j44UsnQNIWdl8gb5L7xX2htKeLw==", "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==",
"dependencies": { "dependencies": {
"browserslist": "^4.22.2", "browserslist": "^4.23.0",
"caniuse-api": "^3.0.0", "caniuse-api": "^3.0.0",
"colord": "^2.9.1", "colord": "^2.9.3",
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
"engines": { "engines": {
@ -709,11 +716,11 @@
} }
}, },
"node_modules/postcss-convert-values": { "node_modules/postcss-convert-values": {
"version": "6.0.2", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.2.tgz", "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz",
"integrity": "sha512-aeBmaTnGQ+NUSVQT8aY0sKyAD/BaLJenEKZ03YK0JnDE1w1Rr8XShoxdal2V2H26xTJKr3v5haByOhJuyT4UYw==", "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==",
"dependencies": { "dependencies": {
"browserslist": "^4.22.2", "browserslist": "^4.23.0",
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
"engines": { "engines": {
@ -724,9 +731,9 @@
} }
}, },
"node_modules/postcss-discard-comments": { "node_modules/postcss-discard-comments": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz",
"integrity": "sha512-f1KYNPtqYLUeZGCHQPKzzFtsHaRuECe6jLakf/RjSRqvF5XHLZnM2+fXLhb8Qh/HBFHs3M4cSLb1k3B899RYIg==", "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==",
"engines": { "engines": {
"node": "^14 || ^16 || >=18.0" "node": "^14 || ^16 || >=18.0"
}, },
@ -735,9 +742,9 @@
} }
}, },
"node_modules/postcss-discard-duplicates": { "node_modules/postcss-discard-duplicates": {
"version": "6.0.1", "version": "6.0.3",
"resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz",
"integrity": "sha512-1hvUs76HLYR8zkScbwyJ8oJEugfPV+WchpnA+26fpJ7Smzs51CzGBHC32RS03psuX/2l0l0UKh2StzNxOrKCYg==", "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==",
"engines": { "engines": {
"node": "^14 || ^16 || >=18.0" "node": "^14 || ^16 || >=18.0"
}, },
@ -746,9 +753,9 @@
} }
}, },
"node_modules/postcss-discard-empty": { "node_modules/postcss-discard-empty": {
"version": "6.0.1", "version": "6.0.3",
"resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz",
"integrity": "sha512-yitcmKwmVWtNsrrRqGJ7/C0YRy53i0mjexBDQ9zYxDwTWVBgbU4+C9jIZLmQlTDT9zhml+u0OMFJh8+31krmOg==", "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==",
"engines": { "engines": {
"node": "^14 || ^16 || >=18.0" "node": "^14 || ^16 || >=18.0"
}, },
@ -757,9 +764,9 @@
} }
}, },
"node_modules/postcss-discard-overridden": { "node_modules/postcss-discard-overridden": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz",
"integrity": "sha512-qs0ehZMMZpSESbRkw1+inkf51kak6OOzNRaoLd/U7Fatp0aN2HQ1rxGOrJvYcRAN9VpX8kUF13R2ofn8OlvFVA==", "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==",
"engines": { "engines": {
"node": "^14 || ^16 || >=18.0" "node": "^14 || ^16 || >=18.0"
}, },
@ -768,12 +775,12 @@
} }
}, },
"node_modules/postcss-merge-longhand": { "node_modules/postcss-merge-longhand": {
"version": "6.0.2", "version": "6.0.5",
"resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.2.tgz", "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz",
"integrity": "sha512-+yfVB7gEM8SrCo9w2lCApKIEzrTKl5yS1F4yGhV3kSim6JzbfLGJyhR1B6X+6vOT0U33Mgx7iv4X9MVWuaSAfw==", "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==",
"dependencies": { "dependencies": {
"postcss-value-parser": "^4.2.0", "postcss-value-parser": "^4.2.0",
"stylehacks": "^6.0.2" "stylehacks": "^6.1.1"
}, },
"engines": { "engines": {
"node": "^14 || ^16 || >=18.0" "node": "^14 || ^16 || >=18.0"
@ -783,14 +790,14 @@
} }
}, },
"node_modules/postcss-merge-rules": { "node_modules/postcss-merge-rules": {
"version": "6.0.3", "version": "6.1.1",
"resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.3.tgz", "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz",
"integrity": "sha512-yfkDqSHGohy8sGYIJwBmIGDv4K4/WrJPX355XrxQb/CSsT4Kc/RxDi6akqn5s9bap85AWgv21ArcUWwWdGNSHA==", "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==",
"dependencies": { "dependencies": {
"browserslist": "^4.22.2", "browserslist": "^4.23.0",
"caniuse-api": "^3.0.0", "caniuse-api": "^3.0.0",
"cssnano-utils": "^4.0.1", "cssnano-utils": "^4.0.2",
"postcss-selector-parser": "^6.0.15" "postcss-selector-parser": "^6.0.16"
}, },
"engines": { "engines": {
"node": "^14 || ^16 || >=18.0" "node": "^14 || ^16 || >=18.0"
@ -800,9 +807,9 @@
} }
}, },
"node_modules/postcss-minify-font-values": { "node_modules/postcss-minify-font-values": {
"version": "6.0.1", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz",
"integrity": "sha512-tIwmF1zUPoN6xOtA/2FgVk1ZKrLcCvE0dpZLtzyyte0j9zUeB8RTbCqrHZGjJlxOvNWKMYtunLrrl7HPOiR46w==", "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==",
"dependencies": { "dependencies": {
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
@ -814,12 +821,12 @@
} }
}, },
"node_modules/postcss-minify-gradients": { "node_modules/postcss-minify-gradients": {
"version": "6.0.1", "version": "6.0.3",
"resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz",
"integrity": "sha512-M1RJWVjd6IOLPl1hYiOd5HQHgpp6cvJVLrieQYS9y07Yo8itAr6jaekzJphaJFR0tcg4kRewCk3kna9uHBxn/w==", "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==",
"dependencies": { "dependencies": {
"colord": "^2.9.1", "colord": "^2.9.3",
"cssnano-utils": "^4.0.1", "cssnano-utils": "^4.0.2",
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
"engines": { "engines": {
@ -830,12 +837,12 @@
} }
}, },
"node_modules/postcss-minify-params": { "node_modules/postcss-minify-params": {
"version": "6.0.2", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.2.tgz", "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz",
"integrity": "sha512-zwQtbrPEBDj+ApELZ6QylLf2/c5zmASoOuA4DzolyVGdV38iR2I5QRMsZcHkcdkZzxpN8RS4cN7LPskOkTwTZw==", "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==",
"dependencies": { "dependencies": {
"browserslist": "^4.22.2", "browserslist": "^4.23.0",
"cssnano-utils": "^4.0.1", "cssnano-utils": "^4.0.2",
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
"engines": { "engines": {
@ -846,11 +853,11 @@
} }
}, },
"node_modules/postcss-minify-selectors": { "node_modules/postcss-minify-selectors": {
"version": "6.0.2", "version": "6.0.4",
"resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.2.tgz", "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz",
"integrity": "sha512-0b+m+w7OAvZejPQdN2GjsXLv5o0jqYHX3aoV0e7RBKPCsB7TYG5KKWBFhGnB/iP3213Ts8c5H4wLPLMm7z28Sg==", "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==",
"dependencies": { "dependencies": {
"postcss-selector-parser": "^6.0.15" "postcss-selector-parser": "^6.0.16"
}, },
"engines": { "engines": {
"node": "^14 || ^16 || >=18.0" "node": "^14 || ^16 || >=18.0"
@ -860,9 +867,9 @@
} }
}, },
"node_modules/postcss-normalize-charset": { "node_modules/postcss-normalize-charset": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz",
"integrity": "sha512-aW5LbMNRZ+oDV57PF9K+WI1Z8MPnF+A8qbajg/T8PP126YrGX1f9IQx21GI2OlGz7XFJi/fNi0GTbY948XJtXg==", "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==",
"engines": { "engines": {
"node": "^14 || ^16 || >=18.0" "node": "^14 || ^16 || >=18.0"
}, },
@ -871,9 +878,9 @@
} }
}, },
"node_modules/postcss-normalize-display-values": { "node_modules/postcss-normalize-display-values": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz",
"integrity": "sha512-mc3vxp2bEuCb4LgCcmG1y6lKJu1Co8T+rKHrcbShJwUmKJiEl761qb/QQCfFwlrvSeET3jksolCR/RZuMURudw==", "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==",
"dependencies": { "dependencies": {
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
@ -885,9 +892,9 @@
} }
}, },
"node_modules/postcss-normalize-positions": { "node_modules/postcss-normalize-positions": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz",
"integrity": "sha512-HRsq8u/0unKNvm0cvwxcOUEcakFXqZ41fv3FOdPn916XFUrympjr+03oaLkuZENz3HE9RrQE9yU0Xv43ThWjQg==", "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==",
"dependencies": { "dependencies": {
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
@ -899,9 +906,9 @@
} }
}, },
"node_modules/postcss-normalize-repeat-style": { "node_modules/postcss-normalize-repeat-style": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz",
"integrity": "sha512-Gbb2nmCy6tTiA7Sh2MBs3fj9W8swonk6lw+dFFeQT68B0Pzwp1kvisJQkdV6rbbMSd9brMlS8I8ts52tAGWmGQ==", "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==",
"dependencies": { "dependencies": {
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
@ -913,9 +920,9 @@
} }
}, },
"node_modules/postcss-normalize-string": { "node_modules/postcss-normalize-string": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz",
"integrity": "sha512-5Fhx/+xzALJD9EI26Aq23hXwmv97Zfy2VFrt5PLT8lAhnBIZvmaT5pQk+NuJ/GWj/QWaKSKbnoKDGLbV6qnhXg==", "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==",
"dependencies": { "dependencies": {
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
@ -927,9 +934,9 @@
} }
}, },
"node_modules/postcss-normalize-timing-functions": { "node_modules/postcss-normalize-timing-functions": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz",
"integrity": "sha512-4zcczzHqmCU7L5dqTB9rzeqPWRMc0K2HoR+Bfl+FSMbqGBUcP5LRfgcH4BdRtLuzVQK1/FHdFoGT3F7rkEnY+g==", "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==",
"dependencies": { "dependencies": {
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
@ -941,11 +948,11 @@
} }
}, },
"node_modules/postcss-normalize-unicode": { "node_modules/postcss-normalize-unicode": {
"version": "6.0.2", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.2.tgz", "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz",
"integrity": "sha512-Ff2VdAYCTGyMUwpevTZPZ4w0+mPjbZzLLyoLh/RMpqUqeQKZ+xMm31hkxBavDcGKcxm6ACzGk0nBfZ8LZkStKA==", "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==",
"dependencies": { "dependencies": {
"browserslist": "^4.22.2", "browserslist": "^4.23.0",
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
"engines": { "engines": {
@ -956,9 +963,9 @@
} }
}, },
"node_modules/postcss-normalize-url": { "node_modules/postcss-normalize-url": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz",
"integrity": "sha512-jEXL15tXSvbjm0yzUV7FBiEXwhIa9H88JOXDGQzmcWoB4mSjZIsmtto066s2iW9FYuIrIF4k04HA2BKAOpbsaQ==", "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==",
"dependencies": { "dependencies": {
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
@ -970,9 +977,9 @@
} }
}, },
"node_modules/postcss-normalize-whitespace": { "node_modules/postcss-normalize-whitespace": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz",
"integrity": "sha512-76i3NpWf6bB8UHlVuLRxG4zW2YykF9CTEcq/9LGAiz2qBuX5cBStadkk0jSkg9a9TCIXbMQz7yzrygKoCW9JuA==", "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==",
"dependencies": { "dependencies": {
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
@ -984,11 +991,11 @@
} }
}, },
"node_modules/postcss-ordered-values": { "node_modules/postcss-ordered-values": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz",
"integrity": "sha512-XXbb1O/MW9HdEhnBxitZpPFbIvDgbo9NK4c/5bOfiKpnIGZDoL2xd7/e6jW5DYLsWxBbs+1nZEnVgnjnlFViaA==", "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==",
"dependencies": { "dependencies": {
"cssnano-utils": "^4.0.1", "cssnano-utils": "^4.0.2",
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
"engines": { "engines": {
@ -999,11 +1006,11 @@
} }
}, },
"node_modules/postcss-reduce-initial": { "node_modules/postcss-reduce-initial": {
"version": "6.0.2", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.2.tgz", "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz",
"integrity": "sha512-YGKalhNlCLcjcLvjU5nF8FyeCTkCO5UtvJEt0hrPZVCTtRLSOH4z00T1UntQPj4dUmIYZgMj8qK77JbSX95hSw==", "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==",
"dependencies": { "dependencies": {
"browserslist": "^4.22.2", "browserslist": "^4.23.0",
"caniuse-api": "^3.0.0" "caniuse-api": "^3.0.0"
}, },
"engines": { "engines": {
@ -1014,9 +1021,9 @@
} }
}, },
"node_modules/postcss-reduce-transforms": { "node_modules/postcss-reduce-transforms": {
"version": "6.0.1", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.1.tgz", "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz",
"integrity": "sha512-fUbV81OkUe75JM+VYO1gr/IoA2b/dRiH6HvMwhrIBSUrxq3jNZQZitSnugcTLDi1KkQh1eR/zi+iyxviUNBkcQ==", "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==",
"dependencies": { "dependencies": {
"postcss-value-parser": "^4.2.0" "postcss-value-parser": "^4.2.0"
}, },
@ -1028,9 +1035,9 @@
} }
}, },
"node_modules/postcss-selector-parser": { "node_modules/postcss-selector-parser": {
"version": "6.0.15", "version": "6.0.16",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz",
"integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==",
"dependencies": { "dependencies": {
"cssesc": "^3.0.0", "cssesc": "^3.0.0",
"util-deprecate": "^1.0.2" "util-deprecate": "^1.0.2"
@ -1040,9 +1047,9 @@
} }
}, },
"node_modules/postcss-svgo": { "node_modules/postcss-svgo": {
"version": "6.0.2", "version": "6.0.3",
"resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.2.tgz", "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz",
"integrity": "sha512-IH5R9SjkTkh0kfFOQDImyy1+mTCb+E830+9SV1O+AaDcoHTvfsvt6WwJeo7KwcHbFnevZVCsXhDmjFiGVuwqFQ==", "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==",
"dependencies": { "dependencies": {
"postcss-value-parser": "^4.2.0", "postcss-value-parser": "^4.2.0",
"svgo": "^3.2.0" "svgo": "^3.2.0"
@ -1055,11 +1062,11 @@
} }
}, },
"node_modules/postcss-unique-selectors": { "node_modules/postcss-unique-selectors": {
"version": "6.0.2", "version": "6.0.4",
"resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.2.tgz", "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz",
"integrity": "sha512-8IZGQ94nechdG7Y9Sh9FlIY2b4uS8/k8kdKRX040XHsS3B6d1HrJAkXrBSsSu4SuARruSsUjW3nlSw8BHkaAYQ==", "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==",
"dependencies": { "dependencies": {
"postcss-selector-parser": "^6.0.15" "postcss-selector-parser": "^6.0.16"
}, },
"engines": { "engines": {
"node": "^14 || ^16 || >=18.0" "node": "^14 || ^16 || >=18.0"
@ -1074,20 +1081,20 @@
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
}, },
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.0.2", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/stylehacks": { "node_modules/stylehacks": {
"version": "6.0.2", "version": "6.1.1",
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.2.tgz", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz",
"integrity": "sha512-00zvJGnCu64EpMjX8b5iCZ3us2Ptyw8+toEkb92VdmkEaRaSGBNKAoK6aWZckhXxmQP8zWiTaFaiMGIU8Ve8sg==", "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==",
"dependencies": { "dependencies": {
"browserslist": "^4.22.2", "browserslist": "^4.23.0",
"postcss-selector-parser": "^6.0.15" "postcss-selector-parser": "^6.0.16"
}, },
"engines": { "engines": {
"node": "^14 || ^16 || >=18.0" "node": "^14 || ^16 || >=18.0"

View file

@ -1,8 +1,8 @@
{ {
"dependencies": { "dependencies": {
"@swc/core": "^1.3.69", "@swc/core": "^1.4.11",
"autoprefixer": "^10.4.14", "autoprefixer": "^10.4.19",
"cssnano": "^6.0.1", "cssnano": "^6.1.2",
"postcss": "^8.4.26" "postcss": "^8.4.38"
} }
} }

View file

@ -168,7 +168,7 @@ $perms = $perms->checkMany([
]); ]);
Template::render('forum.forum', [ Template::render('forum.forum', [
'forum_breadcrumbs' => $forumCategories->getCategoryAncestry($categoryInfo), 'forum_breadcrumbs' => iterator_to_array($forumCategories->getCategoryAncestry($categoryInfo)),
'global_accent_colour' => $forumCategories->getCategoryColour($categoryInfo), 'global_accent_colour' => $forumCategories->getCategoryColour($categoryInfo),
'forum_info' => $categoryInfo, 'forum_info' => $categoryInfo,
'forum_children' => $children, 'forum_children' => $children,

View file

@ -296,7 +296,7 @@ try {
} }
Template::render('forum.posting', [ Template::render('forum.posting', [
'posting_breadcrumbs' => $forumCategories->getCategoryAncestry($categoryInfo), 'posting_breadcrumbs' => iterator_to_array($forumCategories->getCategoryAncestry($categoryInfo)),
'global_accent_colour' => $forumCategories->getCategoryColour($categoryInfo), 'global_accent_colour' => $forumCategories->getCategoryColour($categoryInfo),
'posting_user' => $currentUser, 'posting_user' => $currentUser,
'posting_user_colour' => $usersCtx->getUserColour($currentUser), 'posting_user_colour' => $usersCtx->getUserColour($currentUser),

View file

@ -291,7 +291,11 @@ $postInfos = $forumPosts->getPosts(
if(empty($postInfos)) if(empty($postInfos))
Template::throwError(404); Template::throwError(404);
$originalPostInfo = $forumPosts->getPost(topicInfo: $topicInfo); try {
$originalPostInfo = $forumPosts->getPost(topicInfo: $topicInfo);
} catch(RuntimeException $ex) {
Template::throwError(404);
}
$posts = []; $posts = [];
@ -326,7 +330,7 @@ $perms = $perms->checkMany([
]); ]);
Template::render('forum.topic', [ Template::render('forum.topic', [
'topic_breadcrumbs' => $forumCategories->getCategoryAncestry($topicInfo), 'topic_breadcrumbs' => iterator_to_array($forumCategories->getCategoryAncestry($topicInfo)),
'global_accent_colour' => $forumCategories->getCategoryColour($topicInfo), 'global_accent_colour' => $forumCategories->getCategoryColour($topicInfo),
'topic_info' => $topicInfo, 'topic_info' => $topicInfo,
'category_info' => $categoryInfo, 'category_info' => $categoryInfo,

View file

@ -18,7 +18,7 @@ else
try { try {
$isNew = false; $isNew = false;
$emoteInfo = $emotes->getEmote($emoteId); $emoteInfo = $emotes->getEmote($emoteId);
$emoteStrings = $emotes->getEmoteStrings($emoteInfo); $emoteStrings = iterator_to_array($emotes->getEmoteStrings($emoteInfo));
} catch(RuntimeException $ex) { } catch(RuntimeException $ex) {
Template::throwError(404); Template::throwError(404);
} }

View file

@ -13,7 +13,7 @@ $pagination = new Pagination($auditLog->countLogs(), 50);
if(!$pagination->hasValidOffset()) if(!$pagination->hasValidOffset())
Template::throwError(404); Template::throwError(404);
$logs = $auditLog->getLogs(pagination: $pagination); $logs = iterator_to_array($auditLog->getLogs(pagination: $pagination));
$userInfos = []; $userInfos = [];
$userColours = []; $userColours = [];

View file

@ -106,7 +106,7 @@ if(CSRF::validateRequest() && $canEdit) {
} }
$existingRoles = []; $existingRoles = [];
foreach($roles->getRoles(userInfo: $userInfo) as $roleInfo) foreach(iterator_to_array($roles->getRoles(userInfo: $userInfo)) as $roleInfo)
$existingRoles[$roleInfo->getId()] = $roleInfo; $existingRoles[$roleInfo->getId()] = $roleInfo;
$removeRoles = []; $removeRoles = [];
@ -226,7 +226,7 @@ if(CSRF::validateRequest() && $canEdit) {
return; return;
} }
$rolesAll = $roles->getRoles(); $rolesAll = iterator_to_array($roles->getRoles());
$userRoleIds = $users->hasRoles($userInfo, $rolesAll); $userRoleIds = $users->hasRoles($userInfo, $rolesAll);
Template::render('manage.users.user', [ Template::render('manage.users.user', [

View file

@ -113,7 +113,7 @@ if($isEditing) {
if(!$perms->edit_profile) { if(!$perms->edit_profile) {
$notices[] = 'You\'re not allowed to edit your profile'; $notices[] = 'You\'re not allowed to edit your profile';
} else { } else {
$profileFieldInfos = $profileFields->getFields(); $profileFieldInfos = iterator_to_array($profileFields->getFields());
$profileFieldsSetInfos = []; $profileFieldsSetInfos = [];
$profileFieldsSetValues = []; $profileFieldsSetValues = [];
$profileFieldsRemove = []; $profileFieldsRemove = [];
@ -299,7 +299,7 @@ $profileStats->forum_post_count = $forumCtx->countTotalUserPosts($userInfo);
$profileStats->comments_count = $msz->getComments()->countPosts(userInfo: $userInfo, deleted: false); $profileStats->comments_count = $msz->getComments()->countPosts(userInfo: $userInfo, deleted: false);
if(!$viewingAsGuest) { if(!$viewingAsGuest) {
Template::set('profile_warnings', $usersCtx->getWarnings()->getWarningsWithDefaultBacklog($userInfo)); Template::set('profile_warnings', iterator_to_array($usersCtx->getWarnings()->getWarningsWithDefaultBacklog($userInfo)));
if((!$isBanned || $canEdit)) { if((!$isBanned || $canEdit)) {
$unranked = $cfg->getValues([ $unranked = $cfg->getValues([
@ -323,9 +323,9 @@ if(!$viewingAsGuest) {
); );
$activeTopicInfo = $activeTopicStats->success ? $forumTopics->getTopic(topicId: $activeTopicStats->topicId) : null; $activeTopicInfo = $activeTopicStats->success ? $forumTopics->getTopic(topicId: $activeTopicStats->topicId) : null;
$profileFieldValues = $profileFields->getFieldValues($userInfo); $profileFieldValues = iterator_to_array($profileFields->getFieldValues($userInfo));
$profileFieldInfos = $profileFieldInfos ?? $profileFields->getFields(fieldValueInfos: $isEditing ? null : $profileFieldValues); $profileFieldInfos = $profileFieldInfos ?? iterator_to_array($profileFields->getFields(fieldValueInfos: $isEditing ? null : $profileFieldValues));
$profileFieldFormats = $profileFields->getFieldFormats(fieldValueInfos: $profileFieldValues); $profileFieldFormats = iterator_to_array($profileFields->getFieldFormats(fieldValueInfos: $profileFieldValues));
$profileFieldRawValues = []; $profileFieldRawValues = [];
$profileFieldLinkValues = []; $profileFieldLinkValues = [];

View file

@ -116,7 +116,7 @@ if($isVerifiedRequest && !empty($_POST['current_password'])) {
if($_SERVER['REQUEST_METHOD'] === 'POST' && $isVerifiedRequest) if($_SERVER['REQUEST_METHOD'] === 'POST' && $isVerifiedRequest)
$userInfo = $users->getUser($userInfo->getId(), 'id'); $userInfo = $users->getUser($userInfo->getId(), 'id');
$userRoles = $roles->getRoles(userInfo: $userInfo); $userRoles = iterator_to_array($roles->getRoles(userInfo: $userInfo));
Template::render('settings.account', [ Template::render('settings.account', [
'errors' => $errors, 'errors' => $errors,

View file

@ -15,8 +15,8 @@ $auditLog = $msz->getAuditLog();
$loginHistoryPagination = new Pagination($loginAttempts->countAttempts(userInfo: $currentUser), 5, 'hp'); $loginHistoryPagination = new Pagination($loginAttempts->countAttempts(userInfo: $currentUser), 5, 'hp');
$accountLogPagination = new Pagination($auditLog->countLogs(userInfo: $currentUser), 10, 'ap'); $accountLogPagination = new Pagination($auditLog->countLogs(userInfo: $currentUser), 10, 'ap');
$loginHistory = $loginAttempts->getAttempts(userInfo: $currentUser, pagination: $loginHistoryPagination); $loginHistory = iterator_to_array($loginAttempts->getAttempts(userInfo: $currentUser, pagination: $loginHistoryPagination));
$auditLogs = $auditLog->getLogs(userInfo: $currentUser, pagination: $accountLogPagination); $auditLogs = iterator_to_array($auditLog->getLogs(userInfo: $currentUser, pagination: $accountLogPagination));
Template::render('settings.logs', [ Template::render('settings.logs', [
'login_history_list' => $loginHistory, 'login_history_list' => $loginHistory,

View file

@ -61,7 +61,7 @@ class AuditLog {
UserInfo|string|null $userInfo = null, UserInfo|string|null $userInfo = null,
IPAddress|string|null $remoteAddr = null, IPAddress|string|null $remoteAddr = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
if($userInfo instanceof UserInfo) if($userInfo instanceof UserInfo)
$userInfo = $userInfo->getId(); $userInfo = $userInfo->getId();
if($remoteAddr instanceof IPAddress) if($remoteAddr instanceof IPAddress)
@ -98,13 +98,8 @@ class AuditLog {
} }
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult();
$logs = [];
while($result->next()) return $stmt->getResult()->getIterator(AuditLogInfo::fromResult(...));
$logs[] = new AuditLogInfo($result);
return $logs;
} }
public function createLog( public function createLog(

View file

@ -7,20 +7,24 @@ use Index\Data\IDbResult;
use Index\Net\IPAddress; use Index\Net\IPAddress;
class AuditLogInfo { class AuditLogInfo {
private ?string $userId; public function __construct(
private string $action; private ?string $userId,
private array $params; private string $action,
private int $created; private array $params,
private string $address; private int $created,
private string $country; private string $address,
private string $country,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): AuditLogInfo {
$this->userId = $result->isNull(0) ? null : (string)$result->getInteger(0); return new AuditLogInfo(
$this->action = $result->getString(1); userId: $result->getStringOrNull(0),
$this->params = json_decode($result->getString(2)); action: $result->getString(1),
$this->created = $result->getInteger(3); params: json_decode($result->getString(2)),
$this->address = $result->isNull(4) ? '::1' : $result->getString(4); // apparently this being NULL is possible? created: $result->getInteger(3),
$this->country = $result->getString(5); address: $result->isNull(4) ? '::1' : $result->getString(4), // apparently this being NULL is possible?
country: $result->getString(5),
);
} }
public function hasUserId(): bool { public function hasUserId(): bool {

View file

@ -7,22 +7,26 @@ use Index\Net\IPAddress;
use Misuzu\ClientInfo; use Misuzu\ClientInfo;
class LoginAttemptInfo { class LoginAttemptInfo {
private ?string $userId; public function __construct(
private bool $success; private ?string $userId,
private string $remoteAddr; private bool $success,
private string $countryCode; private string $remoteAddr,
private int $created; private string $countryCode,
private string $userAgent; private int $created,
private string $clientInfo; private string $userAgent,
private string $clientInfo,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): LoginAttemptInfo {
$this->userId = $result->isNull(0) ? null : (string)$result->getInteger(0); return new LoginAttemptInfo(
$this->success = $result->getInteger(1) !== 0; userId: $result->getStringOrNull(0),
$this->remoteAddr = $result->getString(2); success: $result->getBoolean(1),
$this->countryCode = $result->getString(3); remoteAddr: $result->getString(2),
$this->created = $result->getInteger(4); countryCode: $result->getString(3),
$this->userAgent = $result->getString(5); created: $result->getInteger(4),
$this->clientInfo = $result->getString(6); userAgent: $result->getString(5),
clientInfo: $result->getString(6),
);
} }
public function hasUserId(): bool { public function hasUserId(): bool {

View file

@ -83,7 +83,7 @@ class LoginAttempts {
IPAddress|string|null $remoteAddr = null, IPAddress|string|null $remoteAddr = null,
TimeSpan|int|null $timeRange = null, TimeSpan|int|null $timeRange = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
if($userInfo instanceof UserInfo) if($userInfo instanceof UserInfo)
$userInfo = $userInfo->getId(); $userInfo = $userInfo->getId();
if($remoteAddr instanceof IPAddress) if($remoteAddr instanceof IPAddress)
@ -127,13 +127,7 @@ class LoginAttempts {
} }
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(LoginAttemptInfo::fromResult(...));
$attempts = [];
while($result->next())
$attempts[] = new LoginAttemptInfo($result);
return $attempts;
} }
public function recordAttempt( public function recordAttempt(

View file

@ -7,32 +7,36 @@ use Index\Net\IPAddress;
use Misuzu\ClientInfo; use Misuzu\ClientInfo;
class SessionInfo { class SessionInfo {
private string $id; public function __construct(
private string $userId; private string $id,
private string $token; private string $userId,
private string $firstRemoteAddr; private string $token,
private ?string $lastRemoteAddr; private string $firstRemoteAddr,
private string $userAgent; private ?string $lastRemoteAddr,
private string $clientInfo; private string $userAgent,
private string $countryCode; private string $clientInfo,
private int $expires; private string $countryCode,
private bool $bumpExpires; private int $expires,
private int $created; private bool $bumpExpires,
private ?int $lastActive; private int $created,
private ?int $lastActive,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): SessionInfo {
$this->id = (string)$result->getInteger(0); return new SessionInfo(
$this->userId = (string)$result->getInteger(1); id: $result->getString(0),
$this->token = $result->getString(2); userId: $result->getString(1),
$this->firstRemoteAddr = $result->getString(3); token: $result->getString(2),
$this->lastRemoteAddr = $result->isNull(4) ? null : $result->getString(4); firstRemoteAddr: $result->getString(3),
$this->userAgent = $result->getString(5); lastRemoteAddr: $result->getStringOrNull(4),
$this->clientInfo = $result->getString(6); userAgent: $result->getString(5),
$this->countryCode = $result->getString(7); clientInfo: $result->getString(6),
$this->expires = $result->getInteger(8); countryCode: $result->getString(7),
$this->bumpExpires = $result->getInteger(9) !== 0; expires: $result->getInteger(8),
$this->created = $result->getInteger(10); bumpExpires: $result->getBoolean(9),
$this->lastActive = $result->isNull(11) ? null : $result->getInteger(11); created: $result->getInteger(10),
lastActive: $result->getIntegerOrNull(11),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -58,7 +58,7 @@ class Sessions {
public function getSessions( public function getSessions(
UserInfo|string|null $userInfo = null, UserInfo|string|null $userInfo = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
if($userInfo instanceof UserInfo) if($userInfo instanceof UserInfo)
$userInfo = $userInfo->getId(); $userInfo = $userInfo->getId();
@ -85,13 +85,7 @@ class Sessions {
} }
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(SessionInfo::fromResult(...));
$sessions = [];
while($result->next())
$sessions[] = new SessionInfo($result);
return $sessions;
} }
public function getSession( public function getSession(
@ -124,7 +118,7 @@ class Sessions {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('Session not found.'); throw new RuntimeException('Session not found.');
return new SessionInfo($result); return SessionInfo::fromResult($result);
} }
public function createSession( public function createSession(

View file

@ -5,20 +5,24 @@ use Index\DateTime;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class ChangeInfo { class ChangeInfo {
private string $id; public function __construct(
private ?string $userId; private string $id,
private int $action; private ?string $userId,
private int $created; private int $action,
private string $summary; private int $created,
private string $body; private string $summary,
private string $body,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): ChangeInfo {
$this->id = (string)$result->getInteger(0); return new ChangeInfo(
$this->userId = $result->isNull(1) ? null : (string)$result->getInteger(1); id: $result->getString(0),
$this->action = $result->getInteger(2); userId: $result->getStringOrNull(1),
$this->created = $result->getInteger(3); action: $result->getInteger(2),
$this->summary = $result->getString(4); created: $result->getInteger(3),
$this->body = $result->getString(5); summary: $result->getString(4),
body: $result->getString(5),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -121,7 +121,7 @@ class Changelog {
DateTime|int|null $dateTime = null, DateTime|int|null $dateTime = null,
?array $tags = null, ?array $tags = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
if($userInfo instanceof UserInfo) if($userInfo instanceof UserInfo)
$userInfo = $userInfo->getId(); $userInfo = $userInfo->getId();
if($dateTime instanceof DateTime) if($dateTime instanceof DateTime)
@ -169,13 +169,7 @@ class Changelog {
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(ChangeInfo::fromResult(...));
$changes = [];
while($result->next())
$changes[] = new ChangeInfo($result);
return $changes;
} }
public function getChange(string $changeId): ChangeInfo { public function getChange(string $changeId): ChangeInfo {
@ -187,7 +181,7 @@ class Changelog {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('No tag with that ID exists.'); throw new RuntimeException('No tag with that ID exists.');
return new ChangeInfo($result); return ChangeInfo::fromResult($result);
} }
public function createChange( public function createChange(

View file

@ -3,20 +3,12 @@ namespace Misuzu\Changelog;
use ErrorException; use ErrorException;
use RuntimeException; use RuntimeException;
use Index\Routing\Route; use Index\Http\Routing\{HttpGet,RouteHandler};
use Index\Routing\RouteHandler; use Misuzu\{Pagination,SiteInfo,Template};
use Misuzu\Pagination;
use Misuzu\SiteInfo;
use Misuzu\Template;
use Misuzu\Auth\AuthInfo; use Misuzu\Auth\AuthInfo;
use Misuzu\Comments\Comments; use Misuzu\Comments\{Comments,CommentsEx};
use Misuzu\Comments\CommentsEx; use Misuzu\Feeds\{Feed,FeedItem,AtomFeedSerializer,RssFeedSerializer};
use Misuzu\Feeds\Feed; use Misuzu\URLs\{URLInfo,URLRegistry};
use Misuzu\Feeds\FeedItem;
use Misuzu\Feeds\AtomFeedSerializer;
use Misuzu\Feeds\RssFeedSerializer;
use Misuzu\URLs\URLInfo;
use Misuzu\URLs\URLRegistry;
use Misuzu\Users\UsersContext; use Misuzu\Users\UsersContext;
final class ChangelogRoutes extends RouteHandler { final class ChangelogRoutes extends RouteHandler {
@ -34,7 +26,7 @@ final class ChangelogRoutes extends RouteHandler {
return $comments->getCommentsForLayout($categoryName); return $comments->getCommentsForLayout($categoryName);
} }
#[Route('GET', '/changelog')] #[HttpGet('/changelog')]
#[URLInfo('changelog-index', '/changelog', ['date' => '<date>', 'user' => '<user>', 'tags' => '<tags>', 'p' => '<page>'])] #[URLInfo('changelog-index', '/changelog', ['date' => '<date>', 'user' => '<user>', 'tags' => '<tags>', 'p' => '<page>'])]
public function getIndex($response, $request) { public function getIndex($response, $request) {
$filterDate = (string)$request->getParam('date'); $filterDate = (string)$request->getParam('date');
@ -73,15 +65,16 @@ final class ChangelogRoutes extends RouteHandler {
if(!$pagination->hasValidOffset()) if(!$pagination->hasValidOffset())
return 404; return 404;
$changeInfos = $this->changelog->getChanges(userInfo: $filterUser, dateTime: $filterDate, tags: $filterTags, pagination: $pagination);
if(empty($changeInfos))
return 404;
$changes = []; $changes = [];
$changeInfos = $this->changelog->getChanges(userInfo: $filterUser, dateTime: $filterDate, tags: $filterTags, pagination: $pagination);
$commentsCategoryName = null;
foreach($changeInfos as $changeInfo) { foreach($changeInfos as $changeInfo) {
$userInfo = $changeInfo->hasUserId() ? $this->usersCtx->getUserInfo($changeInfo->getUserId()) : null; $userInfo = $changeInfo->hasUserId() ? $this->usersCtx->getUserInfo($changeInfo->getUserId()) : null;
if($commentsCategoryName === null)
$commentsCategoryName = $changeInfo->getCommentsCategoryName();
$changes[] = [ $changes[] = [
'change' => $changeInfo, 'change' => $changeInfo,
'user' => $userInfo, 'user' => $userInfo,
@ -89,17 +82,20 @@ final class ChangelogRoutes extends RouteHandler {
]; ];
} }
if(empty($changes))
return 404;
return Template::renderRaw('changelog.index', [ return Template::renderRaw('changelog.index', [
'changelog_infos' => $changes, 'changelog_infos' => $changes,
'changelog_date' => $filterDate, 'changelog_date' => $filterDate,
'changelog_user' => $filterUser, 'changelog_user' => $filterUser,
'changelog_tags' => $filterTags, 'changelog_tags' => $filterTags,
'changelog_pagination' => $pagination, 'changelog_pagination' => $pagination,
'comments_info' => empty($filterDate) ? null : $this->getCommentsInfo($changeInfos[0]->getCommentsCategoryName()), 'comments_info' => empty($filterDate) && $commentsCategoryName !== null ? null : $this->getCommentsInfo($commentsCategoryName),
]); ]);
} }
#[Route('GET', '/changelog/change/:id')] #[HttpGet('/changelog/change/([0-9]+)')]
#[URLInfo('changelog-change', '/changelog/change/<change>')] #[URLInfo('changelog-change', '/changelog/change/<change>')]
#[URLInfo('changelog-change-comments', '/changelog/change/<change>', fragment: 'comments')] #[URLInfo('changelog-change-comments', '/changelog/change/<change>', fragment: 'comments')]
public function getChange($response, $request, string $changeId) { public function getChange($response, $request, string $changeId) {
@ -148,14 +144,14 @@ final class ChangelogRoutes extends RouteHandler {
return $feed; return $feed;
} }
#[Route('GET', '/changelog.rss')] #[HttpGet('/changelog.rss')]
#[URLInfo('changelog-feed-rss', '/changelog.rss')] #[URLInfo('changelog-feed-rss', '/changelog.rss')]
public function getFeedRSS($response) { public function getFeedRSS($response) {
$response->setContentType('application/rss+xml; charset=utf-8'); $response->setContentType('application/rss+xml; charset=utf-8');
return (new RssFeedSerializer)->serializeFeed($this->createFeed('rss')); return (new RssFeedSerializer)->serializeFeed($this->createFeed('rss'));
} }
#[Route('GET', '/changelog.atom')] #[HttpGet('/changelog.atom')]
#[URLInfo('changelog-feed-atom', '/changelog.atom')] #[URLInfo('changelog-feed-atom', '/changelog.atom')]
public function getFeedAtom($response) { public function getFeedAtom($response) {
$response->setContentType('application/atom+xml; charset=utf-8'); $response->setContentType('application/atom+xml; charset=utf-8');

View file

@ -46,7 +46,7 @@ class Comments {
public function getCategories( public function getCategories(
UserInfo|string|null $owner = null, UserInfo|string|null $owner = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
if($owner instanceof UserInfo) if($owner instanceof UserInfo)
$owner = $owner->getId(); $owner = $owner->getId();
@ -72,13 +72,7 @@ class Comments {
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(CommentsCategoryInfo::fromResult(...));
$categories = [];
while($result->next())
$categories[] = new CommentsCategoryInfo($result);
return $categories;
} }
public function getCategory( public function getCategory(
@ -124,7 +118,7 @@ class Comments {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('Comments category not found.'); throw new RuntimeException('Comments category not found.');
return new CommentsCategoryInfo($result); return CommentsCategoryInfo::fromResult($result);
} }
public function checkCategoryNameExists(string $name): bool { public function checkCategoryNameExists(string $name): bool {
@ -276,7 +270,7 @@ class Comments {
?bool $deleted = null, ?bool $deleted = null,
bool $includeRepliesCount = false, bool $includeRepliesCount = false,
bool $includeVotesCount = false bool $includeVotesCount = false
): array { ): iterable {
if($categoryInfo instanceof CommentsCategoryInfo) if($categoryInfo instanceof CommentsCategoryInfo)
$categoryInfo = $categoryInfo->getId(); $categoryInfo = $categoryInfo->getId();
if($parentInfo instanceof CommentsPostInfo) if($parentInfo instanceof CommentsPostInfo)
@ -330,13 +324,7 @@ class Comments {
$stmt->addParameter(++$args, $userInfo instanceof UserInfo ? $userInfo->getId() : $userInfo); $stmt->addParameter(++$args, $userInfo instanceof UserInfo ? $userInfo->getId() : $userInfo);
$stmt->execute(); $stmt->execute();
$posts = []; return $stmt->getResult()->getIterator(fn($result) => CommentsPostInfo::fromResult($result, $includeRepliesCount, $includeVotesCount));
$result = $stmt->getResult();
while($result->next())
$posts[] = new CommentsPostInfo($result, $includeRepliesCount, $includeVotesCount);
return $posts;
} }
public function getPost( public function getPost(
@ -362,7 +350,7 @@ class Comments {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('No comment with that ID exists.'); throw new RuntimeException('No comment with that ID exists.');
return new CommentsPostInfo($result, $includeRepliesCount, $includeVotesCount); return CommentsPostInfo::fromResult($result, $includeRepliesCount, $includeVotesCount);
} }
public function createPost( public function createPost(

View file

@ -6,20 +6,24 @@ use Index\Data\IDbResult;
use Misuzu\Users\UserInfo; use Misuzu\Users\UserInfo;
class CommentsCategoryInfo { class CommentsCategoryInfo {
private string $id; public function __construct(
private string $name; private string $id,
private ?string $ownerId; private string $name,
private int $created; private ?string $ownerId,
private ?int $locked; private int $created,
private int $comments; private ?int $locked,
private int $comments,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): CommentsCategoryInfo {
$this->id = (string)$result->getInteger(0); return new CommentsCategoryInfo(
$this->name = $result->getString(1); id: $result->getString(0),
$this->ownerId = $result->isNull(2) ? null : (string)$result->getInteger(2); name: $result->getString(1),
$this->created = $result->getInteger(3); ownerId: $result->getStringOrNull(2),
$this->locked = $result->isNull(4) ? null : $result->getInteger(4); created: $result->getInteger(3),
$this->comments = $result->getInteger(5); locked: $result->getIntegerOrNull(4),
comments: $result->getInteger(5),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -5,47 +5,53 @@ use Index\DateTime;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class CommentsPostInfo { class CommentsPostInfo {
private string $id;
private string $categoryId;
private ?string $userId;
private ?string $replyingTo;
private string $body;
private int $created;
private ?int $pinned;
private ?int $updated;
private ?int $deleted;
private int $replies;
private int $votesTotal;
private int $votesPositive;
private int $votesNegative;
public function __construct( public function __construct(
private string $id,
private string $categoryId,
private ?string $userId,
private ?string $replyingTo,
private string $body,
private int $created,
private ?int $pinned,
private ?int $updated,
private ?int $deleted,
private int $replies,
private int $votesTotal,
private int $votesPositive,
private int $votesNegative,
) {}
public static function fromResult(
IDbResult $result, IDbResult $result,
bool $includeRepliesCount = false, bool $includeRepliesCount = false,
bool $includeVotesCount = false bool $includeVotesCount = false
) { ): CommentsPostInfo {
$args = 0; $args = [];
$this->id = (string)$result->getInteger($args); $count = 0;
$this->categoryId = (string)$result->getInteger(++$args);
$this->userId = $result->isNull(++$args) ? null : (string)$result->getInteger($args);
$this->replyingTo = $result->isNull(++$args) ? null : (string)$result->getInteger($args);
$this->body = $result->getString(++$args);
$this->created = $result->getInteger(++$args);
$this->pinned = $result->isNull(++$args) ? null : $result->getInteger($args);
$this->updated = $result->isNull(++$args) ? null : $result->getInteger($args);
$this->deleted = $result->isNull(++$args) ? null : $result->getInteger($args);
$this->replies = $includeRepliesCount ? $result->getInteger(++$args) : 0; $args[] = $result->getString($count); // id
$args[] = $result->getString(++$count); // categoryId
$args[] = $result->getStringOrNull(++$count); // userId
$args[] = $result->getStringOrNull(++$count); // replyingTo
$args[] = $result->getString(++$count); // body
$args[] = $result->getInteger(++$count); // created
$args[] = $result->getIntegerOrNull(++$count); // pinned
$args[] = $result->getIntegerOrNull(++$count); // updated
$args[] = $result->getIntegerOrNull(++$count); // deleted
$args[] = $includeRepliesCount ? $result->getInteger(++$count) : 0;
if($includeVotesCount) { if($includeVotesCount) {
$this->votesTotal = $result->getInteger(++$args); $args[] = $result->getInteger(++$count); // votesTotal
$this->votesPositive = $result->getInteger(++$args); $args[] = $result->getInteger(++$count); // votesPositive
$this->votesNegative = $result->getInteger(++$args); $args[] = $result->getInteger(++$count); // votesNegative
} else { } else {
$this->votesTotal = 0; $args[] = 0;
$this->votesPositive = 0; $args[] = 0;
$this->votesNegative = 0; $args[] = 0;
} }
return new CommentsPostInfo(...$args);
} }
public function getId(): string { public function getId(): string {

View file

@ -5,14 +5,18 @@ use Index\DateTime;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class CounterInfo { class CounterInfo {
private string $name; public function __construct(
private int $value; private string $name,
private int $updated; private int $value,
private int $updated,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): CounterInfo {
$this->name = $result->getString(0); return new CounterInfo(
$this->value = $result->getInteger(1); name: $result->getString(0),
$this->updated = $result->getInteger(2); value: $result->getInteger(1),
updated: $result->getInteger(2),
);
} }
public function getName(): string { public function getName(): string {

View file

@ -25,7 +25,7 @@ class Counters {
public function getCounters( public function getCounters(
?string $orderBy = null, ?string $orderBy = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
$hasOrderBy = $orderBy !== null; $hasOrderBy = $orderBy !== null;
$hasPagination = $pagination !== null; $hasPagination = $pagination !== null;
@ -47,13 +47,7 @@ class Counters {
} }
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(CounterInfo::fromResult(...));
$counters = [];
while($result->next())
$counters[] = new CounterInfo($result);
return $counters;
} }
public function get(array|string $names): array|int { public function get(array|string $names): array|int {

View file

@ -5,16 +5,20 @@ use Stringable;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class EmoteInfo implements Stringable { class EmoteInfo implements Stringable {
private string $id; public function __construct(
private int $order; private string $id,
private int $rank; private int $order,
private string $url; private int $rank,
private string $url,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): EmoteInfo {
$this->id = (string)$result->getInteger(0); return new EmoteInfo(
$this->order = $result->getInteger(1); id: $result->getString(0),
$this->rank = $result->getInteger(2); order: $result->getInteger(1),
$this->url = $result->getString(3); rank: $result->getInteger(2),
url: $result->getString(3),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -5,14 +5,18 @@ use Stringable;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class EmoteStringInfo implements Stringable { class EmoteStringInfo implements Stringable {
private string $emoteId; public function __construct(
private int $order; private string $emoteId,
private string $string; private int $order,
private string $string,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): EmoteStringInfo {
$this->emoteId = (string)$result->getInteger(0); return new EmoteStringInfo(
$this->order = $result->getInteger(1); emoteId: $result->getString(0),
$this->string = $result->getString(2); order: $result->getInteger(1),
string: $result->getString(2),
);
} }
public function getEmoteId(): string { public function getEmoteId(): string {

View file

@ -31,7 +31,7 @@ class Emotes {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('No emoticon with that ID exists.'); throw new RuntimeException('No emoticon with that ID exists.');
return new EmoteInfo($result); return EmoteInfo::fromResult($result);
} }
public static function emoteOrderOptions(): array { public static function emoteOrderOptions(): array {
@ -43,7 +43,7 @@ class Emotes {
?int $minRank = null, ?int $minRank = null,
?string $orderBy = null, ?string $orderBy = null,
?bool $reverse = null ?bool $reverse = null
): array { ): iterable {
$hasMinRank = $minRank !== null; $hasMinRank = $minRank !== null;
$hasOrderBy = $orderBy !== null; $hasOrderBy = $orderBy !== null;
$hasReverse = $reverse !== null; $hasReverse = $reverse !== null;
@ -65,13 +65,7 @@ class Emotes {
$stmt->addParameter(1, $minRank); $stmt->addParameter(1, $minRank);
$stmt->execute(); $stmt->execute();
$emotes = []; return $stmt->getResult()->getIterator(EmoteInfo::fromResult(...));
$result = $stmt->getResult();
while($result->next())
$emotes[] = new EmoteInfo($result);
return $emotes;
} }
private static function checkEmoteUrlInternal(string $url): string { private static function checkEmoteUrlInternal(string $url): string {
@ -156,7 +150,7 @@ class Emotes {
$stmt->execute(); $stmt->execute();
} }
public function getEmoteStrings(EmoteInfo|string $infoOrId): array { public function getEmoteStrings(EmoteInfo|string $infoOrId): iterable {
if($infoOrId instanceof EmoteInfo) if($infoOrId instanceof EmoteInfo)
$infoOrId = $infoOrId->getId(); $infoOrId = $infoOrId->getId();
@ -164,13 +158,7 @@ class Emotes {
$stmt->addParameter(1, $infoOrId); $stmt->addParameter(1, $infoOrId);
$stmt->execute(); $stmt->execute();
$strings = []; return $stmt->getResult()->getIterator(EmoteStringInfo::fromResult(...));
$result = $stmt->getResult();
while($result->next())
$strings[] = new EmoteStringInfo($result);
return $strings;
} }
private static function checkEmoteStringInternal(string $string): string { private static function checkEmoteStringInternal(string $string): string {

View file

@ -12,19 +12,20 @@ use Misuzu\Pagination;
use Misuzu\Users\UserInfo; use Misuzu\Users\UserInfo;
class ForumCategories { class ForumCategories {
private IDbConnection $dbConn;
private DbStatementCache $cache; private DbStatementCache $cache;
public function __construct(IDbConnection $dbConn) { public function __construct(IDbConnection $dbConn) {
$this->dbConn = $dbConn;
$this->cache = new DbStatementCache($dbConn); $this->cache = new DbStatementCache($dbConn);
} }
public static function convertCategoryListToTree( public static function convertCategoryListToTree(
array $catInfos, iterable $catInfos,
ForumCategoryInfo|string|null $parentInfo = null, ForumCategoryInfo|string|null $parentInfo = null,
?Colour $colour = null ?Colour $colour = null
): array { ): array {
if(!is_array($catInfos))
$catInfos = iterator_to_array($catInfos);
$colour ??= Colour::none(); $colour ??= Colour::none();
$tree = []; $tree = [];
$predicate = $parentInfo $predicate = $parentInfo
@ -103,7 +104,7 @@ class ForumCategories {
?bool $hidden = null, ?bool $hidden = null,
bool $asTree = false, bool $asTree = false,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
$isRootParent = false; $isRootParent = false;
$hasParentInfo = $parentInfo !== false; $hasParentInfo = $parentInfo !== false;
$hasType = $type !== null; $hasType = $type !== null;
@ -155,11 +156,7 @@ class ForumCategories {
} }
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); $cats = $stmt->getResult()->getIterator(ForumCategoryInfo::fromResult(...));
$cats = [];
while($result->next())
$cats[] = new ForumCategoryInfo($result);
if($asTree) if($asTree)
$cats = self::convertCategoryListToTree($cats); $cats = self::convertCategoryListToTree($cats);
@ -216,7 +213,7 @@ class ForumCategories {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('Forum category info not found.'); throw new RuntimeException('Forum category info not found.');
return new ForumCategoryInfo($result); return ForumCategoryInfo::fromResult($result);
} }
public function updateCategory( public function updateCategory(
@ -261,7 +258,7 @@ class ForumCategories {
public function getCategoryAncestry( public function getCategoryAncestry(
ForumCategoryInfo|ForumTopicInfo|ForumPostInfo|string $categoryInfo ForumCategoryInfo|ForumTopicInfo|ForumPostInfo|string $categoryInfo
): array { ): iterable {
if($categoryInfo instanceof ForumCategoryInfo) if($categoryInfo instanceof ForumCategoryInfo)
$categoryInfo = $categoryInfo->getId(); $categoryInfo = $categoryInfo->getId();
elseif($categoryInfo instanceof ForumTopicInfo || $categoryInfo instanceof ForumPostInfo) elseif($categoryInfo instanceof ForumTopicInfo || $categoryInfo instanceof ForumPostInfo)
@ -277,13 +274,7 @@ class ForumCategories {
$stmt->addParameter(1, $categoryInfo); $stmt->addParameter(1, $categoryInfo);
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(ForumCategoryInfo::fromResult(...));
$cats = [];
while($result->next())
$cats[] = new ForumCategoryInfo($result);
return $cats;
} }
public function getCategoryChildren( public function getCategoryChildren(
@ -291,7 +282,7 @@ class ForumCategories {
bool $includeSelf = false, bool $includeSelf = false,
?bool $hidden = null, ?bool $hidden = null,
bool $asTree = false bool $asTree = false
): array { ): iterable {
if($parentInfo instanceof ForumCategoryInfo) if($parentInfo instanceof ForumCategoryInfo)
$parentInfo = $parentInfo->getId(); $parentInfo = $parentInfo->getId();
@ -319,11 +310,7 @@ class ForumCategories {
$stmt->addParameter(++$args, $parentInfo); $stmt->addParameter(++$args, $parentInfo);
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); $cats = $stmt->getResult()->getIterator(ForumCategoryInfo::fromResult(...));
$cats = [];
while($result->next())
$cats[] = new ForumCategoryInfo($result);
if($asTree) if($asTree)
$cats = self::convertCategoryListToTree($cats, $parentInfo); $cats = self::convertCategoryListToTree($cats, $parentInfo);

View file

@ -26,38 +26,42 @@ class ForumCategoryInfo {
self::TYPE_DISCUSSION, self::TYPE_DISCUSSION,
]; ];
private string $id; public function __construct(
private int $order; private string $id,
private ?string $parentId; private int $order,
private string $name; private ?string $parentId,
private int $type; private string $name,
private ?string $desc; private int $type,
private ?string $icon; private ?string $desc,
private ?int $colour; private ?string $icon,
private ?string $link; private ?int $colour,
private ?int $clicks; private ?string $link,
private int $created; private ?int $clicks,
private bool $archived; private int $created,
private bool $hidden; private bool $archived,
private int $topicsCount; private bool $hidden,
private int $postsCount; private int $topicsCount,
private int $postsCount,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): ForumCategoryInfo {
$this->id = (string)$result->getInteger(0); return new ForumCategoryInfo(
$this->order = $result->getInteger(1); id: $result->getString(0),
$this->parentId = $result->isNull(2) ? null : (string)$result->getInteger(2); order: $result->getInteger(1),
$this->name = $result->getString(3); parentId: $result->getStringOrNull(2),
$this->type = $result->getInteger(4); name: $result->getString(3),
$this->desc = $result->isNull(5) ? null : $result->getString(5); type: $result->getInteger(4),
$this->icon = $result->isNull(6) ? null : $result->getString(6); desc: $result->getStringOrNull(5),
$this->colour = $result->isNull(7) ? null : $result->getInteger(7); icon: $result->getStringOrNull(6),
$this->link = $result->isNull(8) ? null : $result->getString(8); colour: $result->getIntegerOrNull(7),
$this->clicks = $result->isNull(9) ? null : $result->getInteger(9); link: $result->getStringOrNull(8),
$this->created = $result->getInteger(10); clicks: $result->getIntegerOrNull(9),
$this->archived = $result->getInteger(11) !== 0; created: $result->getInteger(10),
$this->hidden = $result->getInteger(12) !== 0; archived: $result->getBoolean(11),
$this->topicsCount = $result->getInteger(13); hidden: $result->getBoolean(12),
$this->postsCount = $result->getInteger(14); topicsCount: $result->getInteger(13),
postsCount: $result->getInteger(14),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -7,30 +7,34 @@ use Index\Net\IPAddress;
use Misuzu\Parsers\Parser; use Misuzu\Parsers\Parser;
class ForumPostInfo { class ForumPostInfo {
private string $id; public function __construct(
private string $topicId; private string $id,
private string $categoryId; private string $topicId,
private ?string $userId; private string $categoryId,
private string $remoteAddr; private ?string $userId,
private string $body; private string $remoteAddr,
private int $parser; private string $body,
private bool $displaySignature; private int $parser,
private int $created; private bool $displaySignature,
private ?int $edited; private int $created,
private ?int $deleted; private ?int $edited,
private ?int $deleted,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): ForumPostInfo {
$this->id = (string)$result->getInteger(0); return new ForumPostInfo(
$this->topicId = (string)$result->getInteger(1); id: $result->getString(0),
$this->categoryId = (string)$result->getInteger(2); topicId: $result->getString(1),
$this->userId = $result->isNull(3) ? null : (string)$result->getInteger(3); categoryId: $result->getString(2),
$this->remoteAddr = $result->getString(4); userId: $result->getStringOrNull(3),
$this->body = $result->getString(5); remoteAddr: $result->getString(4),
$this->parser = $result->getInteger(6); body: $result->getString(5),
$this->displaySignature = $result->getInteger(7) !== 0; parser: $result->getInteger(6),
$this->created = $result->getInteger(8); displaySignature: $result->getBoolean(7),
$this->edited = $result->isNull(9) ? null : $result->getInteger(9); created: $result->getInteger(8),
$this->deleted = $result->isNull(10) ? null : $result->getInteger(10); edited: $result->getIntegerOrNull(9),
deleted: $result->getIntegerOrNull(10),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -84,7 +84,7 @@ class ForumPosts {
?array $searchQuery = null, ?array $searchQuery = null,
?bool $deleted = null, ?bool $deleted = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
// remove this hack when search server // remove this hack when search server
$hasSearchQuery = $searchQuery !== null; $hasSearchQuery = $searchQuery !== null;
$doSearchOrder = false; $doSearchOrder = false;
@ -189,13 +189,7 @@ class ForumPosts {
} }
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(ForumPostInfo::fromResult(...));
$posts = [];
while($result->next())
$posts[] = new ForumPostInfo($result);
return $posts;
} }
public function getPost( public function getPost(
@ -267,7 +261,7 @@ class ForumPosts {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('Forum post not found.'); throw new RuntimeException('Forum post not found.');
return new ForumPostInfo($result); return ForumPostInfo::fromResult($result);
} }
public function createPost( public function createPost(

View file

@ -17,32 +17,36 @@ class ForumTopicInfo {
'global' => self::TYPE_GLOBAL, 'global' => self::TYPE_GLOBAL,
]; ];
private string $id; public function __construct(
private string $categoryId; private string $id,
private ?string $userId; private string $categoryId,
private int $type; private ?string $userId,
private string $title; private int $type,
private int $postsCount; private string $title,
private int $deletedPostsCount; private int $postsCount,
private int $viewsCount; private int $deletedPostsCount,
private int $created; private int $viewsCount,
private int $bumped; private int $created,
private ?int $deleted; private int $bumped,
private ?int $locked; private ?int $deleted,
private ?int $locked,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): ForumTopicInfo {
$this->id = (string)$result->getInteger(0); return new ForumTopicInfo(
$this->categoryId = (string)$result->getInteger(1); id: $result->getString(0),
$this->userId = $result->isNull(2) ? null : (string)$result->getInteger(2); categoryId: $result->getString(1),
$this->type = $result->getInteger(3); userId: $result->getStringOrNull(2),
$this->title = $result->getString(4); type: $result->getInteger(3),
$this->viewsCount = $result->getInteger(5); title: $result->getString(4),
$this->created = $result->getInteger(6); viewsCount: $result->getInteger(5),
$this->bumped = $result->getInteger(7); created: $result->getInteger(6),
$this->deleted = $result->isNull(8) ? null : $result->getInteger(8); bumped: $result->getInteger(7),
$this->locked = $result->isNull(9) ? null : $result->getInteger(9); deleted: $result->getIntegerOrNull(8),
$this->postsCount = $result->getInteger(10); locked: $result->getIntegerOrNull(9),
$this->deletedPostsCount = $result->getInteger(11); postsCount: $result->getInteger(10),
deletedPostsCount: $result->getInteger(11),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -5,16 +5,20 @@ use Index\DateTime;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class ForumTopicRedirectInfo { class ForumTopicRedirectInfo {
private string $topicId; public function __construct(
private ?string $userId; private string $topicId,
private string $link; private ?string $userId,
private int $created; private string $link,
private int $created,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): ForumTopicRedirectInfo {
$this->topicId = (string)$result->getInteger(0); return new ForumTopicRedirectInfo(
$this->userId = $result->isNull(1) ? null : (string)$result->getInteger(1); topicId: $result->getString(0),
$this->link = $result->getString(2); userId: $result->getStringOrNull(1),
$this->created = $result->getInteger(3); link: $result->getString(2),
created: $result->getInteger(3),
);
} }
public function getTopicId(): string { public function getTopicId(): string {

View file

@ -38,7 +38,7 @@ class ForumTopicRedirects {
public function getTopicRedirects( public function getTopicRedirects(
UserInfo|string|null $userInfo = null, UserInfo|string|null $userInfo = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
if($userInfo instanceof UserInfo) if($userInfo instanceof UserInfo)
$userInfo = $userInfo->getId(); $userInfo = $userInfo->getId();
@ -61,13 +61,7 @@ class ForumTopicRedirects {
} }
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(ForumTopicRedirectInfo::fromResult(...));
$redirs = [];
while($result->next())
$redirs[] = new ForumTopicRedirectInfo($result);
return $redirs;
} }
public function hasTopicRedirect(ForumTopicInfo|string $topicInfo): bool { public function hasTopicRedirect(ForumTopicInfo|string $topicInfo): bool {
@ -97,7 +91,7 @@ class ForumTopicRedirects {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('Could not find that forum topic redirect.'); throw new RuntimeException('Could not find that forum topic redirect.');
return new ForumTopicRedirectInfo($result); return ForumTopicRedirectInfo::fromResult($result);
} }
public function createTopicRedirect( public function createTopicRedirect(

View file

@ -91,7 +91,7 @@ class ForumTopics {
?bool $global = null, ?bool $global = null,
?bool $deleted = null, ?bool $deleted = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
// remove this hack when search server // remove this hack when search server
$hasSearchQuery = $searchQuery !== null; $hasSearchQuery = $searchQuery !== null;
$hasAfterTopicId = false; $hasAfterTopicId = false;
@ -194,13 +194,7 @@ class ForumTopics {
} }
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(ForumTopicInfo::fromResult(...));
$topics = [];
while($result->next())
$topics[] = new ForumTopicInfo($result);
return $topics;
} }
public function getTopic( public function getTopic(
@ -239,7 +233,7 @@ class ForumTopics {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('Forum topic not found.'); throw new RuntimeException('Forum topic not found.');
return new ForumTopicInfo($result); return ForumTopicInfo::fromResult($result);
} }
public function createTopic( public function createTopic(

View file

@ -3,14 +3,10 @@ namespace Misuzu\Home;
use RuntimeException; use RuntimeException;
use Index\DateTime; use Index\DateTime;
use Index\Data\DbTools; use Index\Data\{DbTools,IDbConnection};
use Index\Data\IDbConnection; use Index\Http\Routing\{HttpGet,RouteHandler};
use Index\Routing\Route;
use Index\Routing\RouteHandler;
use Syokuhou\IConfig; use Syokuhou\IConfig;
use Misuzu\Pagination; use Misuzu\{Pagination,SiteInfo,Template};
use Misuzu\SiteInfo;
use Misuzu\Template;
use Misuzu\Auth\AuthInfo; use Misuzu\Auth\AuthInfo;
use Misuzu\Changelog\Changelog; use Misuzu\Changelog\Changelog;
use Misuzu\Comments\Comments; use Misuzu\Comments\Comments;
@ -43,7 +39,7 @@ class HomeRoutes extends RouteHandler {
]); ]);
} }
private function getOnlineUsers(): array { private function getOnlineUsers(): iterable {
return $this->usersCtx->getUsers()->getUsers( return $this->usersCtx->getUsers()->getUsers(
lastActiveInMinutes: 5, lastActiveInMinutes: 5,
deleted: false, deleted: false,
@ -53,14 +49,14 @@ class HomeRoutes extends RouteHandler {
private array $newsCategoryInfos = []; private array $newsCategoryInfos = [];
private function getFeaturedNewsPosts(int $amount, bool $decorate): array { private function getFeaturedNewsPosts(int $amount, bool $decorate): iterable {
$postInfos = $this->news->getPosts( $postInfos = $this->news->getPosts(
onlyFeatured: true, onlyFeatured: true,
pagination: new Pagination($amount) pagination: new Pagination($amount)
); );
if(!$decorate) if(!$decorate)
return $postInfos; return iterator_to_array($postInfos);
$posts = []; $posts = [];
@ -154,7 +150,7 @@ class HomeRoutes extends RouteHandler {
return $topics; return $topics;
} }
#[Route('GET', '/')] #[HttpGet('/')]
#[URLInfo('index', '/')] #[URLInfo('index', '/')]
public function getIndex(...$args) { public function getIndex(...$args) {
return $this->authInfo->isLoggedIn() return $this->authInfo->isLoggedIn()
@ -164,9 +160,9 @@ class HomeRoutes extends RouteHandler {
public function getHome() { public function getHome() {
$stats = $this->getStats(); $stats = $this->getStats();
$onlineUserInfos = $this->getOnlineUsers(); $onlineUserInfos = iterator_to_array($this->getOnlineUsers());
$featuredNews = $this->getFeaturedNewsPosts(5, true); $featuredNews = $this->getFeaturedNewsPosts(5, true);
$changelog = $this->changelog->getChanges(pagination: new Pagination(10)); $changelog = iterator_to_array($this->changelog->getChanges(pagination: new Pagination(10)));
$stats['users:online:recent'] = count($onlineUserInfos); $stats['users:online:recent'] = count($onlineUserInfos);
@ -201,7 +197,7 @@ class HomeRoutes extends RouteHandler {
]); ]);
} }
#[Route('GET', '/_landing')] #[HttpGet('/_landing')]
public function getLanding($response, $request) { public function getLanding($response, $request) {
$config = $this->config->getValues([ $config = $this->config->getValues([
['social.embed_linked:b'], ['social.embed_linked:b'],
@ -221,7 +217,7 @@ class HomeRoutes extends RouteHandler {
} else $linkedData = null; } else $linkedData = null;
$stats = $this->getStats(); $stats = $this->getStats();
$onlineUserInfos = $this->getOnlineUsers(); $onlineUserInfos = iterator_to_array($this->getOnlineUsers());
$featuredNews = $this->getFeaturedNewsPosts(3, false); $featuredNews = $this->getFeaturedNewsPosts(3, false);
$popularTopics = $this->getPopularForumTopics($config['landing.forum_categories']); $popularTopics = $this->getPopularForumTopics($config['landing.forum_categories']);
$activeTopics = $this->getActiveForumTopics($config['landing.forum_categories']); $activeTopics = $this->getActiveForumTopics($config['landing.forum_categories']);

View file

@ -1,8 +1,7 @@
<?php <?php
namespace Misuzu\Info; namespace Misuzu\Info;
use Index\Routing\Route; use Index\Http\Routing\{HttpGet,RouteHandler};
use Index\Routing\RouteHandler;
use Misuzu\Template; use Misuzu\Template;
use Misuzu\Parsers\Parser; use Misuzu\Parsers\Parser;
use Misuzu\URLs\URLInfo; use Misuzu\URLs\URLInfo;
@ -18,23 +17,16 @@ class InfoRoutes extends RouteHandler {
'index' => 'Index Project » %s', 'index' => 'Index Project » %s',
]; ];
private static function checkName(string $name): bool { #[HttpGet('/info')]
return preg_match('#^([A-Za-z0-9_]+)$#', $name) === 1;
}
#[Route('GET', '/info')]
#[URLInfo('info-index', '/info')] #[URLInfo('info-index', '/info')]
public function getIndex() { public function getIndex() {
return Template::renderRaw('info.index'); return Template::renderRaw('info.index');
} }
#[Route('GET', '/info/:name')] #[HttpGet('/info/([A-Za-z0-9_]+)')]
#[URLInfo('info', '/info/<title>')] #[URLInfo('info', '/info/<title>')]
#[URLInfo('info-doc', '/info/<title>')] #[URLInfo('info-doc', '/info/<title>')]
public function getDocsPage($response, $request, string $name) { public function getDocsPage($response, $request, string $name) {
if(!self::checkName($name))
return 404;
return $this->serveMarkdownDocument( return $this->serveMarkdownDocument(
sprintf('%s/%s.md', self::DOCS_PATH, $name) sprintf('%s/%s.md', self::DOCS_PATH, $name)
); );
@ -78,13 +70,11 @@ class InfoRoutes extends RouteHandler {
return ''; return '';
} }
#[Route('GET', '/info/:project/:name')] #[HttpGet('/info/([A-Za-z0-9_]+)/([A-Za-z0-9_]+)')]
#[URLInfo('info-project-doc', '/info/<project>/<title>')] #[URLInfo('info-project-doc', '/info/<project>/<title>')]
public function getProjectPage($response, $request, string $project, string $name) { public function getProjectPage($response, $request, string $project, string $name) {
if(!array_key_exists($project, self::PROJECT_PATHS)) if(!array_key_exists($project, self::PROJECT_PATHS))
return 404; return 404;
if(!self::checkName($name))
return 404;
$projectPath = self::PROJECT_PATHS[$project]; $projectPath = self::PROJECT_PATHS[$project];
$titleSuffix = array_key_exists($project, self::PROJECT_SUFFIXES) ? self::PROJECT_SUFFIXES[$project] : ''; $titleSuffix = array_key_exists($project, self::PROJECT_SUFFIXES) ? self::PROJECT_SUFFIXES[$project] : '';

View file

@ -1,11 +1,8 @@
<?php <?php
namespace Misuzu; namespace Misuzu;
use Index\Routing\Route; use Index\Http\Routing\{HttpGet,RouteHandler};
use Index\Routing\RouteHandler; use Misuzu\URLs\{IURLSource,URLInfo,URLRegistry};
use Misuzu\URLs\IURLSource;
use Misuzu\URLs\URLInfo;
use Misuzu\URLs\URLRegistry;
class LegacyRoutes extends RouteHandler implements IURLSource { class LegacyRoutes extends RouteHandler implements IURLSource {
public function __construct( public function __construct(
@ -124,27 +121,27 @@ class LegacyRoutes extends RouteHandler implements IURLSource {
$urls->register('manage-role', '/manage/users/role.php', ['r' => '<role>']); $urls->register('manage-role', '/manage/users/role.php', ['r' => '<role>']);
} }
#[Route('GET', '/index.php')] #[HttpGet('/index.php')]
public function getIndexPHP($response): void { public function getIndexPHP($response): void {
$response->redirect($this->urls->format('index'), true); $response->redirect($this->urls->format('index'), true);
} }
#[Route('GET', '/info.php')] #[HttpGet('/info.php')]
public function getInfoPHP($response): void { public function getInfoPHP($response): void {
$response->redirect($this->urls->format('info'), true); $response->redirect($this->urls->format('info'), true);
} }
#[Route('GET', '/info.php/:name')] #[HttpGet('/info.php/([A-Za-z0-9_]+)')]
public function getInfoDocsPHP($response, $request, string $name): void { public function getInfoDocsPHP($response, $request, string $name): void {
$response->redirect($this->urls->format('info', ['title' => $name]), true); $response->redirect($this->urls->format('info', ['title' => $name]), true);
} }
#[Route('GET', '/info.php/:project/:name')] #[HttpGet('/info.php/([A-Za-z0-9_]+)/([A-Za-z0-9_]+)')]
public function getInfoProjectPHP($response, $request, string $project, string $name): void { public function getInfoProjectPHP($response, $request, string $project, string $name): void {
$response->redirect($this->urls->format('info', ['title' => $project . '/' . $name]), true); $response->redirect($this->urls->format('info', ['title' => $project . '/' . $name]), true);
} }
#[Route('GET', '/news.php')] #[HttpGet('/news.php')]
public function getNewsPHP($response, $request): void { public function getNewsPHP($response, $request): void {
$postId = (int)($request->getParam('n', FILTER_SANITIZE_NUMBER_INT) ?? $request->getParam('p', FILTER_SANITIZE_NUMBER_INT)); $postId = (int)($request->getParam('n', FILTER_SANITIZE_NUMBER_INT) ?? $request->getParam('p', FILTER_SANITIZE_NUMBER_INT));
@ -159,28 +156,28 @@ class LegacyRoutes extends RouteHandler implements IURLSource {
$response->redirect($location, true); $response->redirect($location, true);
} }
#[Route('GET', '/news.php/rss')] #[HttpGet('/news.php/rss')]
public function getNewsRssPHP($response, $request): void { public function getNewsRssPHP($response, $request): void {
$catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT); $catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
$location = $this->urls->format($catId > 0 ? 'news-category-feed-rss' : 'news-feed-rss', ['category' => $catId]); $location = $this->urls->format($catId > 0 ? 'news-category-feed-rss' : 'news-feed-rss', ['category' => $catId]);
$response->redirect($location, true); $response->redirect($location, true);
} }
#[Route('GET', '/news.php/atom')] #[HttpGet('/news.php/atom')]
public function getNewsAtomPHP($response, $request): void { public function getNewsAtomPHP($response, $request): void {
$catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT); $catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
$location = $this->urls->format($catId > 0 ? 'news-category-feed-atom' : 'news-feed-atom', ['category' => $catId]); $location = $this->urls->format($catId > 0 ? 'news-category-feed-atom' : 'news-feed-atom', ['category' => $catId]);
$response->redirect($location, true); $response->redirect($location, true);
} }
#[Route('GET', '/news/index.php')] #[HttpGet('/news/index.php')]
public function getNewsIndexPHP($response, $request): void { public function getNewsIndexPHP($response, $request): void {
$response->redirect($this->urls->format('news-index', [ $response->redirect($this->urls->format('news-index', [
'page' => $request->getParam('page', FILTER_SANITIZE_NUMBER_INT), 'page' => $request->getParam('page', FILTER_SANITIZE_NUMBER_INT),
]), true); ]), true);
} }
#[Route('GET', '/news/category.php')] #[HttpGet('/news/category.php')]
public function getNewsCategoryPHP($response, $request): void { public function getNewsCategoryPHP($response, $request): void {
$response->redirect($this->urls->format('news-category', [ $response->redirect($this->urls->format('news-category', [
'category' => $request->getParam('c', FILTER_SANITIZE_NUMBER_INT), 'category' => $request->getParam('c', FILTER_SANITIZE_NUMBER_INT),
@ -188,19 +185,19 @@ class LegacyRoutes extends RouteHandler implements IURLSource {
]), true); ]), true);
} }
#[Route('GET', '/news/post.php')] #[HttpGet('/news/post.php')]
public function getNewsPostPHP($response, $request): void { public function getNewsPostPHP($response, $request): void {
$response->redirect($this->urls->format('news-post', [ $response->redirect($this->urls->format('news-post', [
'post' => $request->getParam('p', FILTER_SANITIZE_NUMBER_INT), 'post' => $request->getParam('p', FILTER_SANITIZE_NUMBER_INT),
]), true); ]), true);
} }
#[Route('GET', '/news/feed.php')] #[HttpGet('/news/feed.php')]
public function getNewsFeedPHP($response, $request): int { public function getNewsFeedPHP($response, $request): int {
return 400; return 400;
} }
#[Route('GET', '/news/feed.php/rss')] #[HttpGet('/news/feed.php/rss')]
public function getNewsFeedRssPHP($response, $request): void { public function getNewsFeedRssPHP($response, $request): void {
$catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT); $catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
$response->redirect($this->urls->format( $response->redirect($this->urls->format(
@ -209,7 +206,7 @@ class LegacyRoutes extends RouteHandler implements IURLSource {
), true); ), true);
} }
#[Route('GET', '/news/feed.php/atom')] #[HttpGet('/news/feed.php/atom')]
public function getNewsFeedAtomPHP($response, $request): void { public function getNewsFeedAtomPHP($response, $request): void {
$catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT); $catId = (int)$request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
$response->redirect($this->urls->format( $response->redirect($this->urls->format(
@ -218,7 +215,7 @@ class LegacyRoutes extends RouteHandler implements IURLSource {
), true); ), true);
} }
#[Route('GET', '/changelog.php')] #[HttpGet('/changelog.php')]
public function getChangelogPHP($response, $request): void { public function getChangelogPHP($response, $request): void {
$changeId = $request->getParam('c', FILTER_SANITIZE_NUMBER_INT); $changeId = $request->getParam('c', FILTER_SANITIZE_NUMBER_INT);
if($changeId) { if($changeId) {
@ -232,7 +229,7 @@ class LegacyRoutes extends RouteHandler implements IURLSource {
]), true); ]), true);
} }
#[Route('GET', '/auth.php')] #[HttpGet('/auth.php')]
public function getAuthPHP($response, $request): void { public function getAuthPHP($response, $request): void {
$response->redirect($this->urls->format(match($request->getParam('m')) { $response->redirect($this->urls->format(match($request->getParam('m')) {
'logout' => 'auth-logout', 'logout' => 'auth-logout',
@ -243,44 +240,44 @@ class LegacyRoutes extends RouteHandler implements IURLSource {
}), true); }), true);
} }
#[Route('GET', '/auth')] #[HttpGet('/auth')]
#[Route('GET', '/auth/index.php')] #[HttpGet('/auth/index.php')]
public function getAuthIndexPHP($response, $request): void { public function getAuthIndexPHP($response, $request): void {
$response->redirect($this->urls->format('auth-login'), true); $response->redirect($this->urls->format('auth-login'), true);
} }
#[Route('GET', '/settings.php')] #[HttpGet('/settings.php')]
public function getSettingsPHP($response): void { public function getSettingsPHP($response): void {
$response->redirect($this->urls->format('settings-index'), true); $response->redirect($this->urls->format('settings-index'), true);
} }
#[Route('GET', '/settings')] #[HttpGet('/settings')]
public function getSettingsIndex($response): void { public function getSettingsIndex($response): void {
$response->redirect($this->urls->format('settings-account')); $response->redirect($this->urls->format('settings-account'));
} }
#[Route('GET', '/settings/index.php')] #[HttpGet('/settings/index.php')]
public function getSettingsIndexPHP($response): void { public function getSettingsIndexPHP($response): void {
$response->redirect($this->urls->format('settings-account'), true); $response->redirect($this->urls->format('settings-account'), true);
} }
#[Route('GET', '/manage')] #[HttpGet('/manage')]
#[URLInfo('manage-index', '/manage')] #[URLInfo('manage-index', '/manage')]
public function getManageIndex($response): void { public function getManageIndex($response): void {
$response->redirect($this->urls->format('manage-general-overview')); $response->redirect($this->urls->format('manage-general-overview'));
} }
#[Route('GET', '/manage/index.php')] #[HttpGet('/manage/index.php')]
public function getManageIndexPHP($response): void { public function getManageIndexPHP($response): void {
$response->redirect($this->urls->format('manage-general-overview'), true); $response->redirect($this->urls->format('manage-general-overview'), true);
} }
#[Route('GET', '/manage/news')] #[HttpGet('/manage/news')]
public function getManageNewsIndex($response): void { public function getManageNewsIndex($response): void {
$response->redirect($this->urls->format('manage-news-categories')); $response->redirect($this->urls->format('manage-news-categories'));
} }
#[Route('GET', '/manage/news/index.php')] #[HttpGet('/manage/news/index.php')]
public function getManageNewsIndexPHP($response): void { public function getManageNewsIndexPHP($response): void {
$response->redirect($this->urls->format('manage-news-categories'), true); $response->redirect($this->urls->format('manage-news-categories'), true);
} }

View file

@ -6,32 +6,36 @@ use Index\Data\IDbResult;
use Misuzu\Parsers\Parser; use Misuzu\Parsers\Parser;
class MessageInfo { class MessageInfo {
private string $messageId; public function __construct(
private string $ownerId; private string $messageId,
private ?string $authorId; private string $ownerId,
private ?string $recipientId; private ?string $authorId,
private ?string $replyTo; private ?string $recipientId,
private string $title; private ?string $replyTo,
private string $body; private string $title,
private int $parser; private string $body,
private int $created; private int $parser,
private ?int $sent; private int $created,
private ?int $read; private ?int $sent,
private ?int $deleted; private ?int $read,
private ?int $deleted,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): MessageInfo {
$this->messageId = $result->getString(0); return new MessageInfo(
$this->ownerId = $result->getString(1); messageId: $result->getString(0),
$this->authorId = $result->getStringOrNull(2); ownerId: $result->getString(1),
$this->recipientId = $result->getStringOrNull(3); authorId: $result->getStringOrNull(2),
$this->replyTo = $result->getStringOrNull(4); recipientId: $result->getStringOrNull(3),
$this->title = $result->getString(5); replyTo: $result->getStringOrNull(4),
$this->body = $result->getString(6); title: $result->getString(5),
$this->parser = $result->getInteger(7); body: $result->getString(6),
$this->created = $result->getInteger(8); parser: $result->getInteger(7),
$this->sent = $result->getIntegerOrNull(9); created: $result->getInteger(8),
$this->read = $result->getIntegerOrNull(10); sent: $result->getIntegerOrNull(9),
$this->deleted = $result->getIntegerOrNull(11); read: $result->getIntegerOrNull(10),
deleted: $result->getIntegerOrNull(11),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -11,7 +11,7 @@ use Misuzu\Users\UserInfo;
class MessagesDatabase { class MessagesDatabase {
private DbStatementCache $cache; private DbStatementCache $cache;
public function __construct(private IDbConnection $dbConn) { public function __construct(IDbConnection $dbConn) {
$this->cache = new DbStatementCache($dbConn); $this->cache = new DbStatementCache($dbConn);
} }
@ -92,7 +92,7 @@ class MessagesDatabase {
?bool $read = null, ?bool $read = null,
?bool $deleted = null, ?bool $deleted = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
$hasOwnerInfo = $ownerInfo !== null; $hasOwnerInfo = $ownerInfo !== null;
$hasAuthorInfo = $authorInfo !== null; $hasAuthorInfo = $authorInfo !== null;
$hasRecipientInfo = $recipientInfo !== null; $hasRecipientInfo = $recipientInfo !== null;
@ -153,13 +153,7 @@ class MessagesDatabase {
$stmt->execute(); $stmt->execute();
$infos = []; return $stmt->getResult()->getIterator(MessageInfo::fromResult(...));
$result = $stmt->getResult();
while($result->next())
$infos[] = new MessageInfo($result);
return $infos;
} }
public function getMessageInfo( public function getMessageInfo(
@ -183,7 +177,7 @@ class MessagesDatabase {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('Message not found.'); throw new RuntimeException('Message not found.');
return new MessageInfo($result); return MessageInfo::fromResult($result);
} }
public function createMessage( public function createMessage(

View file

@ -5,7 +5,7 @@ use stdClass;
use InvalidArgumentException; use InvalidArgumentException;
use RuntimeException; use RuntimeException;
use Index\XString; use Index\XString;
use Index\Routing\{Route,RouteHandler}; use Index\Http\Routing\{HttpGet,HttpMiddleware,HttpPost,RouteHandler};
use Syokuhou\IConfig; use Syokuhou\IConfig;
use Misuzu\{CSRF,Pagination,Perm,Template}; use Misuzu\{CSRF,Pagination,Perm,Template};
use Misuzu\Auth\AuthInfo; use Misuzu\Auth\AuthInfo;
@ -33,7 +33,7 @@ class MessagesRoutes extends RouteHandler {
private bool $canSendMessages; private bool $canSendMessages;
#[Route('/messages')] #[HttpMiddleware('/messages')]
public function checkAccess($response, $request) { public function checkAccess($response, $request) {
// should probably be a permission or something too // should probably be a permission or something too
if(!$this->authInfo->isLoggedIn()) if(!$this->authInfo->isLoggedIn())
@ -72,7 +72,7 @@ class MessagesRoutes extends RouteHandler {
return $message; return $message;
} }
#[Route('GET', '/messages')] #[HttpGet('/messages')]
#[URLInfo('messages-index', '/messages', ['folder' => '<folder>', 'page' => '<page>'])] #[URLInfo('messages-index', '/messages', ['folder' => '<folder>', 'page' => '<page>'])]
public function getIndex($response, $request, string $folderName = '') { public function getIndex($response, $request, string $folderName = '') {
$folderName = (string)$request->getParam('folder'); $folderName = (string)$request->getParam('folder');
@ -125,7 +125,7 @@ class MessagesRoutes extends RouteHandler {
]); ]);
} }
#[Route('GET', '/messages/stats')] #[HttpGet('/messages/stats')]
#[URLInfo('messages-stats', '/messages/stats')] #[URLInfo('messages-stats', '/messages/stats')]
public function getStats() { public function getStats() {
$selfInfo = $this->authInfo->getUserInfo(); $selfInfo = $this->authInfo->getUserInfo();
@ -142,7 +142,7 @@ class MessagesRoutes extends RouteHandler {
]; ];
} }
#[Route('POST', '/messages/recipient')] #[HttpPost('/messages/recipient')]
#[URLInfo('messages-recipient', '/messages/recipient')] #[URLInfo('messages-recipient', '/messages/recipient')]
public function postRecipient($response, $request) { public function postRecipient($response, $request) {
if(!$request->isFormContent()) if(!$request->isFormContent())
@ -182,7 +182,7 @@ class MessagesRoutes extends RouteHandler {
]; ];
} }
#[Route('GET', '/messages/compose')] #[HttpGet('/messages/compose')]
#[URLInfo('messages-compose', '/messages/compose', ['recipient' => '<recipient>'])] #[URLInfo('messages-compose', '/messages/compose', ['recipient' => '<recipient>'])]
public function getEditor($response, $request) { public function getEditor($response, $request) {
if(!$this->canSendMessages) if(!$this->canSendMessages)
@ -193,7 +193,7 @@ class MessagesRoutes extends RouteHandler {
]); ]);
} }
#[Route('GET', '/messages/:message')] #[HttpGet('/messages/([A-Za-z0-9]+)')]
#[URLInfo('messages-view', '/messages/<message>')] #[URLInfo('messages-view', '/messages/<message>')]
public function getView($response, $request, string $messageId) { public function getView($response, $request, string $messageId) {
if(strlen($messageId) !== 8) if(strlen($messageId) !== 8)
@ -323,7 +323,7 @@ class MessagesRoutes extends RouteHandler {
return null; return null;
} }
#[Route('POST', '/messages/create')] #[HttpPost('/messages/create')]
#[URLInfo('messages-create', '/messages/create')] #[URLInfo('messages-create', '/messages/create')]
public function postCreate($response, $request) { public function postCreate($response, $request) {
if(!$request->isFormContent()) if(!$request->isFormContent())
@ -427,7 +427,7 @@ class MessagesRoutes extends RouteHandler {
]; ];
} }
#[Route('POST', '/messages/:message')] #[HttpPost('/messages/([A-Za-z0-9]+)')]
#[URLInfo('messages-update', '/messages/<message>')] #[URLInfo('messages-update', '/messages/<message>')]
public function postUpdate($response, $request, string $messageId) { public function postUpdate($response, $request, string $messageId) {
if(!$request->isFormContent()) if(!$request->isFormContent())
@ -518,7 +518,7 @@ class MessagesRoutes extends RouteHandler {
]; ];
} }
#[Route('POST', '/messages/mark')] #[HttpPost('/messages/mark')]
#[URLInfo('messages-mark', '/messages/mark')] #[URLInfo('messages-mark', '/messages/mark')]
public function postMark($response, $request) { public function postMark($response, $request) {
if(!$request->isFormContent()) if(!$request->isFormContent())
@ -549,16 +549,16 @@ class MessagesRoutes extends RouteHandler {
return []; return [];
} }
#[Route('POST', '/messages/delete')] #[HttpPost('/messages/delete')]
#[URLInfo('messages-delete', '/messages/delete')] #[URLInfo('messages-delete', '/messages/delete')]
public function postDelete($response, $request) { public function postDelete($response, $request) {
if(!$request->isFormContent()) if(!$request->isFormContent())
return 400; return 400;
$content = $request->getContent(); $content = $request->getContent();
$messages = explode(',', (string)$content->getParam('messages'));
if(empty($messages)) $messages = (string)$content->getParam('messages');
if($messages === '')
return [ return [
'error' => [ 'error' => [
'name' => 'msgs:empty', 'name' => 'msgs:empty',
@ -566,6 +566,8 @@ class MessagesRoutes extends RouteHandler {
], ],
]; ];
$messages = explode(',', $messages);
$this->msgsCtx->getDatabase()->deleteMessages( $this->msgsCtx->getDatabase()->deleteMessages(
$this->authInfo->getUserInfo(), $this->authInfo->getUserInfo(),
$messages $messages
@ -574,16 +576,16 @@ class MessagesRoutes extends RouteHandler {
return []; return [];
} }
#[Route('POST', '/messages/restore')] #[HttpPost('/messages/restore')]
#[URLInfo('messages-restore', '/messages/restore')] #[URLInfo('messages-restore', '/messages/restore')]
public function postRestore($response, $request) { public function postRestore($response, $request) {
if(!$request->isFormContent()) if(!$request->isFormContent())
return 400; return 400;
$content = $request->getContent(); $content = $request->getContent();
$messages = explode(',', (string)$content->getParam('messages'));
if(empty($messages)) $messages = (string)$content->getParam('messages');
if($messages === '')
return [ return [
'error' => [ 'error' => [
'name' => 'msgs:empty', 'name' => 'msgs:empty',
@ -591,6 +593,8 @@ class MessagesRoutes extends RouteHandler {
], ],
]; ];
$messages = explode(',', $messages);
$this->msgsCtx->getDatabase()->restoreMessages( $this->msgsCtx->getDatabase()->restoreMessages(
$this->authInfo->getUserInfo(), $this->authInfo->getUserInfo(),
$messages $messages
@ -599,16 +603,16 @@ class MessagesRoutes extends RouteHandler {
return []; return [];
} }
#[Route('POST', '/messages/nuke')] #[HttpPost('/messages/nuke')]
#[URLInfo('messages-nuke', '/messages/nuke')] #[URLInfo('messages-nuke', '/messages/nuke')]
public function postNuke($response, $request) { public function postNuke($response, $request) {
if(!$request->isFormContent()) if(!$request->isFormContent())
return 400; return 400;
$content = $request->getContent(); $content = $request->getContent();
$messages = explode(',', (string)$content->getParam('messages'));
if(empty($messages)) $messages = (string)$content->getParam('messages');
if($messages === '')
return [ return [
'error' => [ 'error' => [
'name' => 'msgs:empty', 'name' => 'msgs:empty',
@ -616,6 +620,8 @@ class MessagesRoutes extends RouteHandler {
], ],
]; ];
$messages = explode(',', $messages);
$this->msgsCtx->getDatabase()->nukeMessages( $this->msgsCtx->getDatabase()->nukeMessages(
$this->authInfo->getUserInfo(), $this->authInfo->getUserInfo(),
$messages $messages

View file

@ -212,7 +212,6 @@ class MisuzuContext {
$routingCtx = new RoutingContext(); $routingCtx = new RoutingContext();
$this->urls = $routingCtx->getURLs(); $this->urls = $routingCtx->getURLs();
$routingCtx->registerDefaultErrorPages();
$routingCtx->register(new \Misuzu\Home\HomeRoutes( $routingCtx->register(new \Misuzu\Home\HomeRoutes(
$this->config, $this->config,
@ -263,6 +262,7 @@ class MisuzuContext {
$routingCtx->register(new \Misuzu\SharpChat\SharpChatRoutes( $routingCtx->register(new \Misuzu\SharpChat\SharpChatRoutes(
$this->config->scopeTo('sockChat'), $this->config->scopeTo('sockChat'),
$this->config->scopeTo('impersonate'),
$this->urls, $this->urls,
$this->usersCtx, $this->usersCtx,
$this->authCtx, $this->authCtx,

View file

@ -41,7 +41,7 @@ class News {
public function getCategories( public function getCategories(
?bool $hidden = null, ?bool $hidden = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
$hasHidden = $hidden !== null; $hasHidden = $hidden !== null;
$hasPagination = $pagination !== null; $hasPagination = $pagination !== null;
@ -61,13 +61,7 @@ class News {
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(NewsCategoryInfo::fromResult(...));
$categories = [];
while($result->next())
$categories[] = new NewsCategoryInfo($result);
return $categories;
} }
public function getCategory( public function getCategory(
@ -107,7 +101,7 @@ class News {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('News category not found.'); throw new RuntimeException('News category not found.');
return new NewsCategoryInfo($result); return NewsCategoryInfo::fromResult($result);
} }
public function createCategory( public function createCategory(
@ -224,7 +218,7 @@ class News {
bool $includeScheduled = false, bool $includeScheduled = false,
bool $includeDeleted = false, bool $includeDeleted = false,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
if($categoryInfo instanceof NewsCategoryInfo) if($categoryInfo instanceof NewsCategoryInfo)
$categoryInfo = $categoryInfo->getId(); $categoryInfo = $categoryInfo->getId();
@ -271,13 +265,7 @@ class News {
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(NewsPostInfo::fromResult(...));
$posts = [];
while($result->next())
$posts[] = new NewsPostInfo($result);
return $posts;
} }
public function getPost(string $postId): NewsPostInfo { public function getPost(string $postId): NewsPostInfo {
@ -289,7 +277,7 @@ class News {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('No news post with that ID exists.'); throw new RuntimeException('No news post with that ID exists.');
return new NewsPostInfo($result); return NewsPostInfo::fromResult($result);
} }
public function createPost( public function createPost(

View file

@ -5,20 +5,24 @@ use Index\DateTime;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class NewsCategoryInfo { class NewsCategoryInfo {
private string $id; public function __construct(
private string $name; private string $id,
private string $description; private string $name,
private bool $hidden; private string $description,
private int $created; private bool $hidden,
private int $posts; private int $created,
private int $posts,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): NewsCategoryInfo {
$this->id = (string)$result->getInteger(0); return new NewsCategoryInfo(
$this->name = $result->getString(1); id: $result->getString(0),
$this->description = $result->getString(2); name: $result->getString(1),
$this->hidden = $result->getInteger(3) !== 0; description: $result->getString(2),
$this->created = $result->getInteger(4); hidden: $result->getBoolean(3),
$this->posts = $result->getInteger(5); created: $result->getInteger(4),
posts: $result->getInteger(5),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -5,30 +5,34 @@ use Index\DateTime;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class NewsPostInfo { class NewsPostInfo {
private string $id; public function __construct(
private string $categoryId; private string $id,
private ?string $userId; private string $categoryId,
private ?string $commentsSectionId; private ?string $userId,
private bool $featured; private ?string $commentsSectionId,
private string $title; private bool $featured,
private string $body; private string $title,
private int $scheduled; private string $body,
private int $created; private int $scheduled,
private int $updated; private int $created,
private ?int $deleted; private int $updated,
private ?int $deleted,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): NewsPostInfo {
$this->id = (string)$result->getInteger(0); return new NewsPostInfo(
$this->categoryId = (string)$result->getInteger(1); id: $result->getString(0),
$this->userId = $result->isNull(2) ? null : (string)$result->getInteger(2); categoryId: $result->getString(1),
$this->commentsSectionId = $result->isNull(3) ? null : (string)$result->getInteger(3); userId: $result->getStringOrNull(2),
$this->featured = $result->getInteger(4) !== 0; commentsSectionId: $result->getStringOrNull(3),
$this->title = $result->getString(5); featured: $result->getBoolean(4),
$this->body = $result->getString(6); title: $result->getString(5),
$this->scheduled = $result->getInteger(7); body: $result->getString(6),
$this->created = $result->getInteger(8); scheduled: $result->getInteger(7),
$this->updated = $result->getInteger(9); created: $result->getInteger(8),
$this->deleted = $result->isNull(10) ? null : $result->getInteger(10); updated: $result->getInteger(9),
deleted: $result->getIntegerOrNull(10),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -3,24 +3,14 @@ namespace Misuzu\News;
use RuntimeException; use RuntimeException;
use Index\DateTime; use Index\DateTime;
use Index\Data\DbTools; use Index\Data\{DbTools,IDbConnection};
use Index\Data\IDbConnection; use Index\Http\Routing\{HttpGet,RouteHandler};
use Index\Routing\Route; use Misuzu\{Pagination,SiteInfo,Template};
use Index\Routing\RouteHandler;
use Misuzu\Pagination;
use Misuzu\SiteInfo;
use Misuzu\Template;
use Misuzu\Auth\AuthInfo; use Misuzu\Auth\AuthInfo;
use Misuzu\Comments\Comments; use Misuzu\Comments\{Comments,CommentsCategory,CommentsEx};
use Misuzu\Comments\CommentsCategory; use Misuzu\Feeds\{Feed,FeedItem,AtomFeedSerializer,RssFeedSerializer};
use Misuzu\Comments\CommentsEx;
use Misuzu\Feeds\Feed;
use Misuzu\Feeds\FeedItem;
use Misuzu\Feeds\AtomFeedSerializer;
use Misuzu\Feeds\RssFeedSerializer;
use Misuzu\Parsers\Parser; use Misuzu\Parsers\Parser;
use Misuzu\URLs\URLInfo; use Misuzu\URLs\{URLInfo,URLRegistry};
use Misuzu\URLs\URLRegistry;
use Misuzu\Users\UsersContext; use Misuzu\Users\UsersContext;
class NewsRoutes extends RouteHandler { class NewsRoutes extends RouteHandler {
@ -91,7 +81,7 @@ class NewsRoutes extends RouteHandler {
return $posts; return $posts;
} }
#[Route('GET', '/news')] #[HttpGet('/news')]
#[URLInfo('news-index', '/news', ['p' => '<page>'])] #[URLInfo('news-index', '/news', ['p' => '<page>'])]
public function getIndex() { public function getIndex() {
$categories = $this->news->getCategories(hidden: false); $categories = $this->news->getCategories(hidden: false);
@ -109,24 +99,21 @@ class NewsRoutes extends RouteHandler {
]); ]);
} }
#[Route('GET', '/news.rss')] #[HttpGet('/news.rss')]
#[URLInfo('news-feed-rss', '/news.rss')] #[URLInfo('news-feed-rss', '/news.rss')]
public function getFeedRss($response) { public function getFeedRss($response) {
return $this->getFeed($response, 'rss'); return $this->getFeed($response, 'rss');
} }
#[Route('GET', '/news.atom')] #[HttpGet('/news.atom')]
#[URLInfo('news-feed-atom', '/news.atom')] #[URLInfo('news-feed-atom', '/news.atom')]
public function getFeedAtom($response) { public function getFeedAtom($response) {
return $this->getFeed($response, 'atom'); return $this->getFeed($response, 'atom');
} }
#[Route('GET', '/news/:category')] #[HttpGet('/news/([0-9]+)(?:\.(rss|atom))?')]
#[URLInfo('news-category', '/news/<category>', ['p' => '<page>'])] #[URLInfo('news-category', '/news/<category>', ['p' => '<page>'])]
public function getCategory($response, $request, string $fileName) { public function getCategory($response, $request, string $categoryId, string $type = '') {
$categoryId = pathinfo($fileName, PATHINFO_FILENAME);
$type = pathinfo($fileName, PATHINFO_EXTENSION);
try { try {
$categoryInfo = $this->news->getCategory(categoryId: $categoryId); $categoryInfo = $this->news->getCategory(categoryId: $categoryId);
} catch(RuntimeException $ex) { } catch(RuntimeException $ex) {
@ -163,7 +150,7 @@ class NewsRoutes extends RouteHandler {
return $this->getFeed($response, 'atom', $categoryInfo); return $this->getFeed($response, 'atom', $categoryInfo);
} }
#[Route('GET', '/news/post/:id')] #[HttpGet('/news/post/([0-9]+)')]
#[URLInfo('news-post', '/news/post/<post>')] #[URLInfo('news-post', '/news/post/<post>')]
#[URLInfo('news-post-comments', '/news/post/<post>', fragment: 'comments')] #[URLInfo('news-post-comments', '/news/post/<post>', fragment: 'comments')]
public function getPost($response, $request, string $postId) { public function getPost($response, $request, string $postId) {

View file

@ -6,24 +6,30 @@ use Index\Data\IDbResult;
class PermissionInfo implements IPermissionResult { class PermissionInfo implements IPermissionResult {
use PermissionResultShared; use PermissionResultShared;
private ?string $userId;
private ?string $roleId;
private ?string $forumCategoryId;
private string $category;
private int $allow;
private int $deny;
private int $calculated; private int $calculated;
public function __construct(IDbResult $result) { public function __construct(
$this->userId = $result->isNull(0) ? null : $result->getString(0); private ?string $userId,
$this->roleId = $result->isNull(1) ? null : $result->getString(1); private ?string $roleId,
$this->forumCategoryId = $result->isNull(2) ? null : $result->getString(2); private ?string $forumCategoryId,
$this->category = $result->getString(3); private string $category,
$this->allow = $result->getInteger(4); private int $allow,
$this->deny = $result->getInteger(5); private int $deny,
) {
$this->calculated = $this->allow & ~$this->deny; $this->calculated = $this->allow & ~$this->deny;
} }
public static function fromResult(IDbResult $result): PermissionInfo {
return new PermissionInfo(
userId: $result->getStringOrNull(0),
roleId: $result->getStringOrNull(1),
forumCategoryId: $result->getStringOrNull(2),
category: $result->getString(3),
allow: $result->getInteger(4),
deny: $result->getInteger(5),
);
}
public function hasUserId(): bool { public function hasUserId(): bool {
return $this->userId !== null; return $this->userId !== null;
} }

View file

@ -76,11 +76,11 @@ class Permissions {
$result = $stmt->getResult(); $result = $stmt->getResult();
if(is_string($categoryNames)) if(is_string($categoryNames))
return $result->next() ? new PermissionInfo($result) : null; return $result->next() ? PermissionInfo::fromResult($result) : null;
$perms = []; $perms = [];
while($result->next()) while($result->next())
$perms[$result->getString(3)] = new PermissionInfo($result); $perms[$result->getString(3)] = PermissionInfo::fromResult($result);
return $perms; return $perms;
} }

View file

@ -4,18 +4,22 @@ namespace Misuzu\Profile;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class ProfileFieldFormatInfo { class ProfileFieldFormatInfo {
private string $id; public function __construct(
private string $fieldId; private string $id,
private ?string $regex; private string $fieldId,
private ?string $linkFormat; private ?string $regex,
private string $displayFormat; private ?string $linkFormat,
private string $displayFormat,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): ProfileFieldFormatInfo {
$this->id = (string)$result->getInteger(0); return new ProfileFieldFormatInfo(
$this->fieldId = (string)$result->getInteger(1); id: $result->getString(0),
$this->regex = $result->isNull(2) ? null : $result->getString(2); fieldId: $result->getString(1),
$this->linkFormat = $result->isNull(3) ? null : $result->getString(3); regex: $result->getStringOrNull(2),
$this->displayFormat = $result->getString(4); linkFormat: $result->getStringOrNull(3),
displayFormat: $result->getString(4),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -4,18 +4,22 @@ namespace Misuzu\Profile;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class ProfileFieldInfo { class ProfileFieldInfo {
private string $id; public function __construct(
private int $order; private string $id,
private string $name; private int $order,
private string $title; private string $name,
private string $regex; private string $title,
private string $regex,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): ProfileFieldInfo {
$this->id = (string)$result->getInteger(0); return new ProfileFieldInfo(
$this->order = $result->getInteger(1); id: $result->getString(0),
$this->name = $result->getString(2); order: $result->getInteger(1),
$this->title = $result->getString(3); name: $result->getString(2),
$this->regex = $result->getString(4); title: $result->getString(3),
regex: $result->getString(4),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -4,16 +4,20 @@ namespace Misuzu\Profile;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class ProfileFieldValueInfo { class ProfileFieldValueInfo {
private string $fieldId; public function __construct(
private string $userId; private string $fieldId,
private string $formatId; private string $userId,
private string $value; private string $formatId,
private string $value,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): ProfileFieldValueInfo {
$this->fieldId = (string)$result->getInteger(0); return new ProfileFieldValueInfo(
$this->userId = (string)$result->getInteger(1); fieldId: $result->getString(0),
$this->formatId = (string)$result->getInteger(2); userId: $result->getString(1),
$this->value = $result->getString(3); formatId: $result->getString(2),
value: $result->getString(3)
);
} }
public function getFieldId(): string { public function getFieldId(): string {

View file

@ -16,10 +16,15 @@ class ProfileFields {
$this->cache = new DbStatementCache($dbConn); $this->cache = new DbStatementCache($dbConn);
} }
public function getFields(?array $fieldValueInfos = null): array { public function getFields(?iterable $fieldValueInfos = null): iterable {
$hasFieldValueInfos = $fieldValueInfos !== null; $hasFieldValueInfos = $fieldValueInfos !== null;
if($hasFieldValueInfos && empty($fieldValueInfos)) if($hasFieldValueInfos) {
return []; if(!is_array($fieldValueInfos))
$fieldValueInfos = iterator_to_array($fieldValueInfos);
if(empty($fieldValueInfos))
return [];
}
$query = 'SELECT field_id, field_order, field_key, field_title, field_regex FROM msz_profile_fields'; $query = 'SELECT field_id, field_order, field_key, field_title, field_regex FROM msz_profile_fields';
if($hasFieldValueInfos) if($hasFieldValueInfos)
@ -37,13 +42,8 @@ class ProfileFields {
} }
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult();
$fields = [];
while($result->next()) return $stmt->getResult()->getIterator(ProfileFieldInfo::fromResult(...));
$fields[] = new ProfileFieldInfo($result);
return $fields;
} }
public function getField(string $fieldId): ProfileFieldInfo { public function getField(string $fieldId): ProfileFieldInfo {
@ -55,20 +55,30 @@ class ProfileFields {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('No field found with the provided field id.'); throw new RuntimeException('No field found with the provided field id.');
return new ProfileFieldInfo($result); return ProfileFieldInfo::fromResult($result);
} }
public function getFieldFormats( public function getFieldFormats(
?array $fieldInfos = null, ?iterable $fieldInfos = null,
?array $fieldValueInfos = null ?iterable $fieldValueInfos = null
): array { ): iterable {
$hasFieldInfos = $fieldInfos !== null; $hasFieldInfos = $fieldInfos !== null;
$hasFieldValueInfos = $fieldValueInfos !== null; $hasFieldValueInfos = $fieldValueInfos !== null;
if($hasFieldInfos && empty($fieldInfos)) if($hasFieldInfos) {
return []; if(!is_array($fieldInfos))
if($hasFieldValueInfos && empty($fieldValueInfos)) $fieldInfos = iterator_to_array($fieldInfos);
return [];
if(empty($fieldInfos))
return [];
}
if($hasFieldValueInfos) {
if(!is_array($fieldValueInfos))
$fieldValueInfos = iterator_to_array($fieldValueInfos);
if(empty($fieldValueInfos))
return [];
}
$args = 0; $args = 0;
$query = 'SELECT format_id, field_id, format_regex, format_link, format_display FROM msz_profile_fields_formats'; $query = 'SELECT format_id, field_id, format_regex, format_link, format_display FROM msz_profile_fields_formats';
@ -101,13 +111,8 @@ class ProfileFields {
} }
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult();
$formats = [];
while($result->next()) return $stmt->getResult()->getIterator(ProfileFieldFormatInfo::fromResult(...));
$formats[] = new ProfileFieldFormatInfo($result);
return $formats;
} }
public function getFieldFormat(string $formatId): ProfileFieldFormatInfo { public function getFieldFormat(string $formatId): ProfileFieldFormatInfo {
@ -119,7 +124,7 @@ class ProfileFields {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('No format found with the provided format id.'); throw new RuntimeException('No format found with the provided format id.');
return new ProfileFieldFormatInfo($result); return ProfileFieldFormatInfo::fromResult($result);
} }
public function selectFieldFormat( public function selectFieldFormat(
@ -138,10 +143,10 @@ class ProfileFields {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('Could not determine an appropriate format for this field (missing default formatting)'); throw new RuntimeException('Could not determine an appropriate format for this field (missing default formatting)');
return new ProfileFieldFormatInfo($result); return ProfileFieldFormatInfo::fromResult($result);
} }
public function getFieldValues(UserInfo|string $userInfo): array { public function getFieldValues(UserInfo|string $userInfo): iterable {
if($userInfo instanceof UserInfo) if($userInfo instanceof UserInfo)
$userInfo = $userInfo->getId(); $userInfo = $userInfo->getId();
@ -151,13 +156,7 @@ class ProfileFields {
$stmt->addParameter(1, $userInfo); $stmt->addParameter(1, $userInfo);
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(ProfileFieldValueInfo::fromResult(...));
$values = [];
while($result->next())
$values[] = new ProfileFieldValueInfo($result);
return $values;
} }
public function getFieldValue( public function getFieldValue(
@ -179,7 +178,7 @@ class ProfileFields {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('No value for this field and user combination found.'); throw new RuntimeException('No value for this field and user combination found.');
return new ProfileFieldValueInfo($result); return ProfileFieldValueInfo::fromResult($result);
} }
public function setFieldValues( public function setFieldValues(

View file

@ -1,21 +1,16 @@
<?php <?php
namespace Misuzu; namespace Misuzu;
use Index\Http\HttpFx; use Index\Http\Routing\{HttpRouter,IRouter,IRouteHandler};
use Index\Http\HttpRequest; use Misuzu\URLs\{IURLSource,URLInfo,URLRegistry};
use Index\Routing\IRouter;
use Index\Routing\IRouteHandler;
use Misuzu\URLs\IURLSource;
use Misuzu\URLs\URLInfo;
use Misuzu\URLs\URLRegistry;
class RoutingContext { class RoutingContext {
private URLRegistry $urls; private URLRegistry $urls;
private HttpFx $router; private HttpRouter $router;
public function __construct() { public function __construct() {
$this->urls = new URLRegistry; $this->urls = new URLRegistry;
$this->router = new HttpFx; $this->router = new HttpRouter(errorHandler: new RoutingErrorHandler);
$this->router->use('/', fn($resp) => $resp->setPoweredBy('Misuzu')); $this->router->use('/', fn($resp) => $resp->setPoweredBy('Misuzu'));
} }
@ -27,25 +22,6 @@ class RoutingContext {
return $this->router; return $this->router;
} }
public function registerDefaultErrorPages(): void {
$this->router->addErrorHandler(400, fn($resp) => $resp->setContent(Template::renderRaw('errors.400')));
$this->router->addErrorHandler(403, fn($resp) => $resp->setContent(Template::renderRaw('errors.403')));
$this->router->addErrorHandler(404, fn($resp) => $resp->setContent(Template::renderRaw('errors.404')));
$this->router->addErrorHandler(500, fn($resp) => $resp->setContent(file_get_contents(MSZ_TEMPLATES . '/500.html')));
$this->router->addErrorHandler(503, fn($resp) => $resp->setContent(file_get_contents(MSZ_TEMPLATES . '/503.html')));
}
public static function registerSimpleErrorPages(IRouter $router, string $path): void {
if($router instanceof HttpFx)
$router->use($path, function() use($router) {
$router->addErrorHandler(400, fn($resp) => $resp->setContent('HTTP 400'));
$router->addErrorHandler(403, fn($resp) => $resp->setContent('HTTP 403'));
$router->addErrorHandler(404, fn($resp) => $resp->setContent('HTTP 404'));
$router->addErrorHandler(500, fn($resp) => $resp->setContent('HTTP 500'));
$router->addErrorHandler(503, fn($resp) => $resp->setContent('HTTP 503'));
});
}
public function register(IRouteHandler|IURLSource $handler): void { public function register(IRouteHandler|IURLSource $handler): void {
if($handler instanceof IRouteHandler) if($handler instanceof IRouteHandler)
$this->router->register($handler); $this->router->register($handler);
@ -54,7 +30,7 @@ class RoutingContext {
URLInfo::handleAttributes($this->urls, $handler); URLInfo::handleAttributes($this->urls, $handler);
} }
public function dispatch(?HttpRequest $request = null): void { public function dispatch(...$args): void {
$this->router->dispatch($request); $this->router->dispatch(...$args);
} }
} }

View file

@ -0,0 +1,29 @@
<?php
namespace Misuzu;
use Index\Http\{HttpResponseBuilder,HttpRequest};
use Index\Http\ErrorHandling\HtmlErrorHandler;
class RoutingErrorHandler extends HtmlErrorHandler {
public function handle(HttpResponseBuilder $response, HttpRequest $request, int $code, string $message): void {
if(str_starts_with($request->getPath(), '/_')) {
$response->setTypePlain();
$response->setContent(sprintf('HTTP %03d', $code));
return;
}
if($code === 500 || $code === 503) {
$response->setTypeHTML();
$response->setContent(file_get_contents(sprintf('%s/%03d.html', MSZ_TEMPLATES, $code)));
return;
}
if($code === 401 || $code === 403 || $code === 404) {
$response->setTypeHTML();
$response->setContent(Template::renderRaw(sprintf('errors.%03d', $code)));
return;
}
parent::handle($response, $request, $code, $message);
}
}

View file

@ -3,9 +3,7 @@ namespace Misuzu\Satori;
use RuntimeException; use RuntimeException;
use Index\Colour\Colour; use Index\Colour\Colour;
use Index\Routing\IRouter; use Index\Http\Routing\{HttpGet,HttpMiddleware,RouteHandler};
use Index\Routing\IRouteHandler;
use Index\Routing\Route;
use Syokuhou\IConfig; use Syokuhou\IConfig;
use Misuzu\Pagination; use Misuzu\Pagination;
use Misuzu\RoutingContext; use Misuzu\RoutingContext;
@ -13,7 +11,7 @@ use Misuzu\Forum\ForumContext;
use Misuzu\Profile\ProfileFields; use Misuzu\Profile\ProfileFields;
use Misuzu\Users\UsersContext; use Misuzu\Users\UsersContext;
final class SatoriRoutes implements IRouteHandler { final class SatoriRoutes extends RouteHandler {
public function __construct( public function __construct(
private IConfig $config, private IConfig $config,
private UsersContext $usersCtx, private UsersContext $usersCtx,
@ -21,12 +19,7 @@ final class SatoriRoutes implements IRouteHandler {
private ProfileFields $profileFields private ProfileFields $profileFields
) {} ) {}
public function registerRoutes(IRouter $router): void { #[HttpMiddleware('/_satori')]
RoutingContext::registerSimpleErrorPages($router, '/_satori');
Route::handleAttributes($router, $this);
}
#[Route('/_satori')]
public function verifyRequest($response, $request) { public function verifyRequest($response, $request) {
$secretKey = $this->config->getString('secret'); $secretKey = $this->config->getString('secret');
@ -46,7 +39,7 @@ final class SatoriRoutes implements IRouteHandler {
} }
} }
#[Route('GET', '/_satori/get-profile-field')] #[HttpGet('/_satori/get-profile-field')]
public function getProfileField($response, $request): array { public function getProfileField($response, $request): array {
$userId = (string)$request->getParam('user', FILTER_SANITIZE_NUMBER_INT); $userId = (string)$request->getParam('user', FILTER_SANITIZE_NUMBER_INT);
$fieldId = (string)$request->getParam('field', FILTER_SANITIZE_NUMBER_INT); $fieldId = (string)$request->getParam('field', FILTER_SANITIZE_NUMBER_INT);
@ -62,7 +55,7 @@ final class SatoriRoutes implements IRouteHandler {
]; ];
} }
#[Route('GET', '/_satori/get-recent-forum-posts')] #[HttpGet('/_satori/get-recent-forum-posts')]
public function getRecentForumPosts($response, $request): array { public function getRecentForumPosts($response, $request): array {
$categoryIds = $this->config->getArray('forum.categories'); $categoryIds = $this->config->getArray('forum.categories');
if(empty($categoryIds)) if(empty($categoryIds))
@ -104,7 +97,7 @@ final class SatoriRoutes implements IRouteHandler {
return $posts; return $posts;
} }
#[Route('GET', '/_satori/get-recent-registrations')] #[HttpGet('/_satori/get-recent-registrations')]
public function getRecentRegistrations($response, $request) { public function getRecentRegistrations($response, $request) {
$batchSize = $this->config->getInteger('users.batch', 10); $batchSize = $this->config->getInteger('users.batch', 10);
$backlogDays = $this->config->getInteger('users.backlog', 7); $backlogDays = $this->config->getInteger('users.backlog', 7);

View file

@ -3,25 +3,21 @@ namespace Misuzu\SharpChat;
use RuntimeException; use RuntimeException;
use Index\Colour\Colour; use Index\Colour\Colour;
use Index\Routing\IRouter; use Index\Http\Routing\{HandlerAttribute,HttpDelete,HttpGet,HttpOptions,HttpPost,RouteHandler};
use Index\Routing\IRouteHandler;
use Index\Routing\Route;
use Syokuhou\IConfig; use Syokuhou\IConfig;
use Misuzu\RoutingContext; use Misuzu\RoutingContext;
use Misuzu\Auth\AuthContext; use Misuzu\Auth\{AuthContext,AuthInfo,Sessions};
use Misuzu\Auth\AuthInfo;
use Misuzu\Auth\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; use Misuzu\Users\{Bans,UsersContext,UserInfo};
use Misuzu\Users\UsersContext;
final class SharpChatRoutes implements IRouteHandler { final class SharpChatRoutes extends RouteHandler {
private string $hashKey; private string $hashKey;
public function __construct( public function __construct(
private IConfig $config, private IConfig $config,
private IConfig $impersonateConfig, // this sucks lol
private URLRegistry $urls, private URLRegistry $urls,
private UsersContext $usersCtx, private UsersContext $usersCtx,
private AuthContext $authCtx, private AuthContext $authCtx,
@ -32,13 +28,8 @@ final class SharpChatRoutes implements IRouteHandler {
$this->hashKey = $this->config->getString('hashKey', 'woomy'); $this->hashKey = $this->config->getString('hashKey', 'woomy');
} }
public function registerRoutes(IRouter $router): void { #[HttpOptions('/_sockchat/emotes')]
RoutingContext::registerSimpleErrorPages($router, '/_sockchat'); #[HttpGet('/_sockchat/emotes')]
Route::handleAttributes($router, $this);
}
#[Route('OPTIONS', '/_sockchat/emotes')]
#[Route('GET', '/_sockchat/emotes')]
public function getEmotes($response, $request): array|int { public function getEmotes($response, $request): array|int {
$response->setHeader('Access-Control-Allow-Origin', '*'); $response->setHeader('Access-Control-Allow-Origin', '*');
$response->setHeader('Access-Control-Allow-Methods', 'GET'); $response->setHeader('Access-Control-Allow-Methods', 'GET');
@ -66,7 +57,7 @@ final class SharpChatRoutes implements IRouteHandler {
return $out; return $out;
} }
#[Route('GET', '/_sockchat/login')] #[HttpGet('/_sockchat/login')]
public function getLogin($response, $request) { public function getLogin($response, $request) {
if(!$this->authInfo->isLoggedIn()) { if(!$this->authInfo->isLoggedIn()) {
$response->redirect($this->urls->format('auth-login')); $response->redirect($this->urls->format('auth-login'));
@ -79,8 +70,16 @@ final class SharpChatRoutes implements IRouteHandler {
)); ));
} }
#[Route('OPTIONS', '/_sockchat/token')] private function canImpersonateUserId(UserInfo $impersonator, string $targetId): bool {
#[Route('GET', '/_sockchat/token')] if($impersonator->isSuperUser())
return true;
$whitelist = $this->impersonateConfig->getArray(sprintf('allow.u%s', $impersonator->getId()));
return in_array($targetId, $whitelist, true);
}
#[HttpOptions('/_sockchat/token')]
#[HttpGet('/_sockchat/token')]
public function getToken($response, $request) { public function getToken($response, $request) {
$host = $request->hasHeader('Host') ? $request->getHeaderFirstLine('Host') : ''; $host = $request->hasHeader('Host') ? $request->getHeaderFirstLine('Host') : '';
$origin = $request->hasHeader('Origin') ? $request->getHeaderFirstLine('Origin') : ''; $origin = $request->hasHeader('Origin') ? $request->getHeaderFirstLine('Origin') : '';
@ -121,7 +120,7 @@ final class SharpChatRoutes implements IRouteHandler {
return ['ok' => false, 'err' => 'user']; return ['ok' => false, 'err' => 'user'];
$userInfo = $this->usersCtx->getUsers()->getUser($sessionInfo->getUserId(), 'id'); $userInfo = $this->usersCtx->getUsers()->getUser($sessionInfo->getUserId(), 'id');
$userId = $tokenInfo->hasImpersonatedUserId() && $userInfo->isSuperUser() $userId = $tokenInfo->hasImpersonatedUserId() && $this->canImpersonateUserId($userInfo, $tokenInfo->getImpersonatedUserId())
? $tokenInfo->getImpersonatedUserId() ? $tokenInfo->getImpersonatedUserId()
: $userInfo->getId(); : $userInfo->getId();
@ -134,7 +133,7 @@ final class SharpChatRoutes implements IRouteHandler {
]; ];
} }
#[Route('POST', '/_sockchat/bump')] #[HttpPost('/_sockchat/bump')]
public function postBump($response, $request) { public function postBump($response, $request) {
if(!$request->hasHeader('X-SharpChat-Signature')) if(!$request->hasHeader('X-SharpChat-Signature'))
return 400; return 400;
@ -164,7 +163,7 @@ final class SharpChatRoutes implements IRouteHandler {
$this->usersCtx->getUsers()->recordUserActivity($userId, remoteAddr: $ipAddr); $this->usersCtx->getUsers()->recordUserActivity($userId, remoteAddr: $ipAddr);
} }
#[Route('POST', '/_sockchat/verify')] #[HttpPost('/_sockchat/verify')]
public function postVerify($response, $request) { public function postVerify($response, $request) {
if(!$request->hasHeader('X-SharpChat-Signature')) if(!$request->hasHeader('X-SharpChat-Signature'))
return 400; return 400;
@ -215,7 +214,7 @@ final class SharpChatRoutes implements IRouteHandler {
$this->authCtx->getSessions()->recordSessionActivity(sessionInfo: $sessionInfo, remoteAddr: $ipAddress); $this->authCtx->getSessions()->recordSessionActivity(sessionInfo: $sessionInfo, remoteAddr: $ipAddress);
$userInfo = $this->usersCtx->getUsers()->getUser($sessionInfo->getUserId(), 'id'); $userInfo = $this->usersCtx->getUsers()->getUser($sessionInfo->getUserId(), 'id');
if($tokenInfo->hasImpersonatedUserId() && $userInfo->isSuperUser()) { if($tokenInfo->hasImpersonatedUserId() && $this->canImpersonateUserId($userInfo, $tokenInfo->getImpersonatedUserId())) {
$userInfoReal = $userInfo; $userInfoReal = $userInfo;
try { try {
@ -245,7 +244,7 @@ final class SharpChatRoutes implements IRouteHandler {
]; ];
} }
#[Route('GET', '/_sockchat/bans/list')] #[HttpGet('/_sockchat/bans/list')]
public function getBanList($response, $request) { public function getBanList($response, $request) {
if(!$request->hasHeader('X-SharpChat-Signature')) if(!$request->hasHeader('X-SharpChat-Signature'))
return 400; return 400;
@ -280,7 +279,7 @@ final class SharpChatRoutes implements IRouteHandler {
return $list; return $list;
} }
#[Route('GET', '/_sockchat/bans/check')] #[HttpGet('/_sockchat/bans/check')]
public function getBanCheck($response, $request) { public function getBanCheck($response, $request) {
if(!$request->hasHeader('X-SharpChat-Signature')) if(!$request->hasHeader('X-SharpChat-Signature'))
return 400; return 400;
@ -318,7 +317,7 @@ final class SharpChatRoutes implements IRouteHandler {
]; ];
} }
#[Route('POST', '/_sockchat/bans/create')] #[HttpPost('/_sockchat/bans/create')]
public function postBanCreate($response, $request): int { public function postBanCreate($response, $request): int {
if(!$request->hasHeader('X-SharpChat-Signature') || !$request->isFormContent()) if(!$request->hasHeader('X-SharpChat-Signature') || !$request->isFormContent())
return 400; return 400;
@ -392,7 +391,7 @@ final class SharpChatRoutes implements IRouteHandler {
return 201; return 201;
} }
#[Route('DELETE', '/_sockchat/bans/revoke')] #[HttpDelete('/_sockchat/bans/revoke')]
public function deleteBanRevoke($response, $request): int { public function deleteBanRevoke($response, $request): int {
if(!$request->hasHeader('X-SharpChat-Signature')) if(!$request->hasHeader('X-SharpChat-Signature'))
return 400; return 400;

View file

@ -1,9 +1,6 @@
<?php <?php
namespace Misuzu; namespace Misuzu;
use Index\Routing\IRouter;
use Index\Http\HttpFx;
final class Tools { final class Tools {
public static function isLocalURL( public static function isLocalURL(
string $url, string $url,

View file

@ -3,14 +3,11 @@ namespace Misuzu\Users\Assets;
use InvalidArgumentException; use InvalidArgumentException;
use RuntimeException; use RuntimeException;
use Index\Routing\Route; use Index\Http\Routing\{HttpGet,RouteHandler};
use Index\Routing\RouteHandler;
use Misuzu\Perm; use Misuzu\Perm;
use Misuzu\Auth\AuthInfo; use Misuzu\Auth\AuthInfo;
use Misuzu\URLs\URLInfo; use Misuzu\URLs\{URLInfo,URLRegistry};
use Misuzu\URLs\URLRegistry; use Misuzu\Users\{UsersContext,UserInfo};
use Misuzu\Users\UsersContext;
use Misuzu\Users\UserInfo;
class AssetsRoutes extends RouteHandler { class AssetsRoutes extends RouteHandler {
public function __construct( public function __construct(
@ -29,11 +26,10 @@ class AssetsRoutes extends RouteHandler {
return true; return true;
} }
#[Route('GET', '/assets/avatar')] #[HttpGet('/assets/avatar')]
#[Route('GET', '/assets/avatar/:filename')] #[HttpGet('/assets/avatar/([0-9]+)(?:\.[a-z]+)?')]
#[URLInfo('user-avatar', '/assets/avatar/<user>', ['res' => '<res>'])] #[URLInfo('user-avatar', '/assets/avatar/<user>', ['res' => '<res>'])]
public function getAvatar($response, $request, string $fileName = '') { public function getAvatar($response, $request, string $userId = '') {
$userId = pathinfo($fileName, PATHINFO_FILENAME);
$assetInfo = new StaticUserImageAsset(MSZ_PUBLIC . '/images/no-avatar.png', MSZ_PUBLIC); $assetInfo = new StaticUserImageAsset(MSZ_PUBLIC . '/images/no-avatar.png', MSZ_PUBLIC);
try { try {
@ -52,12 +48,10 @@ class AssetsRoutes extends RouteHandler {
$this->serveAsset($response, $request, $assetInfo); $this->serveAsset($response, $request, $assetInfo);
} }
#[Route('GET', '/assets/profile-background')] #[HttpGet('/assets/profile-background')]
#[Route('GET', '/assets/profile-background/:filename')] #[HttpGet('/assets/profile-background/([0-9]+)(?:\.[a-z]+)?')]
#[URLInfo('user-background', '/assets/profile-background/<user>')] #[URLInfo('user-background', '/assets/profile-background/<user>')]
public function getProfileBackground($response, $request, string $fileName = '') { public function getProfileBackground($response, $request, string $userId = '') {
$userId = pathinfo($fileName, PATHINFO_FILENAME);
try { try {
$userInfo = $this->usersCtx->getUserInfo($userId); $userInfo = $this->usersCtx->getUserInfo($userId);
} catch(RuntimeException $ex) { } catch(RuntimeException $ex) {
@ -78,7 +72,7 @@ class AssetsRoutes extends RouteHandler {
$this->serveAsset($response, $request, $assetInfo); $this->serveAsset($response, $request, $assetInfo);
} }
#[Route('GET', '/user-assets.php')] #[HttpGet('/user-assets.php')]
public function getUserAssets($response, $request) { public function getUserAssets($response, $request) {
$userId = (string)$request->getParam('u', FILTER_SANITIZE_NUMBER_INT); $userId = (string)$request->getParam('u', FILTER_SANITIZE_NUMBER_INT);
$mode = (string)$request->getParam('m'); $mode = (string)$request->getParam('m');

View file

@ -5,24 +5,28 @@ use Index\DateTime;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class BanInfo { class BanInfo {
private string $id; public function __construct(
private string $userId; private string $id,
private ?string $modId; private string $userId,
private int $severity; private ?string $modId,
private string $publicReason; private int $severity,
private string $privateReason; private string $publicReason,
private int $created; private string $privateReason,
private ?int $expires; private int $created,
private ?int $expires,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): BanInfo {
$this->id = (string)$result->getInteger(0); return new BanInfo(
$this->userId = (string)$result->getInteger(1); id: $result->getString(0),
$this->modId = $result->isNull(2) ? null : (string)$result->getInteger(2); userId: $result->getString(1),
$this->severity = $result->getInteger(3); modId: $result->getStringOrNull(2),
$this->publicReason = $result->getString(4); severity: $result->getInteger(3),
$this->privateReason = $result->getString(5); publicReason: $result->getString(4),
$this->created = $result->getInteger(6); privateReason: $result->getString(5),
$this->expires = $result->isNull(7) ? null : $result->getInteger(7); created: $result->getInteger(6),
expires: $result->getIntegerOrNull(7),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -64,7 +64,7 @@ class Bans {
?bool $activeOnly = null, ?bool $activeOnly = null,
?bool $activeFirst = null, ?bool $activeFirst = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
if($userInfo instanceof UserInfo) if($userInfo instanceof UserInfo)
$userInfo = $userInfo->getId(); $userInfo = $userInfo->getId();
@ -101,13 +101,7 @@ class Bans {
} }
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(BanInfo::fromResult(...));
$bans = [];
while($result->next())
$bans[] = new BanInfo($result);
return $bans;
} }
public function getBan(string $banId): BanInfo { public function getBan(string $banId): BanInfo {
@ -119,7 +113,7 @@ class Bans {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('No ban with ID $banId found.'); throw new RuntimeException('No ban with ID $banId found.');
return new BanInfo($result); return BanInfo::fromResult($result);
} }
public function countActiveBans( public function countActiveBans(
@ -153,7 +147,7 @@ class Bans {
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); $result = $stmt->getResult();
return $result->next() ? new BanInfo($result) : null; return $result->next() ? BanInfo::fromResult($result) : null;
} }
public function createBan( public function createBan(

View file

@ -5,20 +5,24 @@ use Index\DateTime;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class ModNoteInfo { class ModNoteInfo {
private string $noteId; public function __construct(
private string $userId; private string $noteId,
private ?string $authorId; private string $userId,
private int $created; private ?string $authorId,
private string $title; private int $created,
private string $body; private string $title,
private string $body,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): ModNoteInfo {
$this->noteId = (string)$result->getInteger(0); return new ModNoteInfo(
$this->userId = (string)$result->getInteger(1); noteId: $result->getString(0),
$this->authorId = $result->isNull(2) ? null : (string)$result->getInteger(2); userId: $result->getString(1),
$this->created = $result->getInteger(3); authorId: $result->getStringOrNull(2),
$this->title = $result->getString(4); created: $result->getInteger(3),
$this->body = $result->getString(5); title: $result->getString(4),
body: $result->getString(5)
);
} }
public function getId(): string { public function getId(): string {

View file

@ -59,7 +59,7 @@ class ModNotes {
UserInfo|string|null $userInfo = null, UserInfo|string|null $userInfo = null,
UserInfo|string|null $authorInfo = null, UserInfo|string|null $authorInfo = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
if($userInfo instanceof UserInfo) if($userInfo instanceof UserInfo)
$userInfo = $userInfo->getId(); $userInfo = $userInfo->getId();
if($authorInfo instanceof UserInfo) if($authorInfo instanceof UserInfo)
@ -93,13 +93,7 @@ class ModNotes {
} }
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(ModNoteInfo::fromResult(...));
$notes = [];
while($result->next())
$notes[] = new ModNoteInfo($result);
return $notes;
} }
public function getNote(string $noteId): ModNoteInfo { public function getNote(string $noteId): ModNoteInfo {
@ -111,7 +105,7 @@ class ModNotes {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('No note with ID $noteId found.'); throw new RuntimeException('No note with ID $noteId found.');
return new ModNoteInfo($result); return ModNoteInfo::fromResult($result);
} }
public function createNote( public function createNote(

View file

@ -7,26 +7,30 @@ use Index\Colour\Colour;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class RoleInfo implements Stringable { class RoleInfo implements Stringable {
private string $id; public function __construct(
private int $rank; private string $id,
private string $name; private int $rank,
private ?string $title; private string $name,
private ?string $description; private ?string $title,
private bool $hidden; private ?string $description,
private bool $leavable; private bool $hidden,
private ?int $colour; private bool $leavable,
private int $created; private ?int $colour,
private int $created,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): RoleInfo {
$this->id = (string)$result->getInteger(0); return new RoleInfo(
$this->rank = $result->getInteger(1); id: $result->getString(0),
$this->name = $result->getString(2); rank: $result->getInteger(1),
$this->title = $result->isNull(3) ? null : $result->getString(3); name: $result->getString(2),
$this->description = $result->isNull(4) ? null : $result->getString(4); title: $result->getStringOrNull(3),
$this->hidden = $result->getInteger(5) !== 0; description: $result->getStringOrNull(4),
$this->leavable = $result->getInteger(6) !== 0; hidden: $result->getBoolean(5),
$this->colour = $result->isNull(7) ? null : $result->getInteger(7); leavable: $result->getBoolean(6),
$this->created = $result->getInteger(8); colour: $result->getIntegerOrNull(7),
created: $result->getInteger(8),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -58,7 +58,7 @@ class Roles {
UserInfo|string|null $userInfo = null, UserInfo|string|null $userInfo = null,
?bool $hidden = null, ?bool $hidden = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
if($userInfo instanceof UserInfo) if($userInfo instanceof UserInfo)
$userInfo = $userInfo->getId(); $userInfo = $userInfo->getId();
@ -87,13 +87,7 @@ class Roles {
} }
$stmt->execute(); $stmt->execute();
$roles = []; return $stmt->getResult()->getIterator(RoleInfo::fromResult(...));
$result = $stmt->getResult();
while($result->next())
$roles[] = new RoleInfo($result);
return $roles;
} }
public function getRole(string $roleId): RoleInfo { public function getRole(string $roleId): RoleInfo {
@ -105,7 +99,7 @@ class Roles {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('Could not find role with ID $roleId.'); throw new RuntimeException('Could not find role with ID $roleId.');
return new RoleInfo($result); return RoleInfo::fromResult($result);
} }
public function createRole( public function createRole(

View file

@ -9,50 +9,54 @@ use Index\Net\IPAddress;
use Misuzu\Parsers\Parser; use Misuzu\Parsers\Parser;
class UserInfo { class UserInfo {
private string $id; public function __construct(
private string $name; private string $id,
private ?string $passwordHash; private string $name,
private string $emailAddr; private ?string $passwordHash,
private string $registerRemoteAddr; private string $emailAddr,
private string $lastRemoteAddr; private string $registerRemoteAddr,
private bool $super; private string $lastRemoteAddr,
private string $countryCode; private bool $super,
private ?int $colour; private string $countryCode,
private int $created; private ?int $colour,
private ?int $lastActive; private int $created,
private ?int $deleted; private ?int $lastActive,
private ?string $displayRoleId; private ?int $deleted,
private ?string $totpKey; private ?string $displayRoleId,
private ?string $aboutContent; private ?string $totpKey,
private int $aboutParser; private ?string $aboutContent,
private ?string $signatureContent; private int $aboutParser,
private int $signatureParser; private ?string $signatureContent,
private ?string $birthdate; private int $signatureParser,
private ?int $backgroundSettings; private ?string $birthdate,
private ?string $title; private ?int $backgroundSettings,
private ?string $title,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): self {
$this->id = (string)$result->getInteger(0); return new UserInfo(
$this->name = $result->getString(1); id: $result->getString(0),
$this->passwordHash = $result->isNull(2) ? null : $result->getString(2); name: $result->getString(1),
$this->emailAddr = $result->getString(3); passwordHash: $result->getStringOrNull(2),
$this->registerRemoteAddr = $result->getString(4); emailAddr: $result->getString(3),
$this->lastRemoteAddr = $result->isNull(5) ? null : $result->getString(5); registerRemoteAddr: $result->getString(4),
$this->super = $result->getInteger(6) !== 0; lastRemoteAddr: $result->getStringOrNull(5),
$this->countryCode = $result->getString(7); super: $result->getBoolean(6),
$this->colour = $result->isNull(8) ? null : $result->getInteger(8); countryCode: $result->getString(7),
$this->created = $result->getInteger(9); colour: $result->getIntegerOrNull(8),
$this->lastActive = $result->isNull(10) ? null : $result->getInteger(10); created: $result->getInteger(9),
$this->deleted = $result->isNull(11) ? null : $result->getInteger(11); lastActive: $result->getIntegerOrNull(10),
$this->displayRoleId = $result->isNull(12) ? null : (string)$result->getInteger(12); deleted: $result->getIntegerOrNull(11),
$this->totpKey = $result->isNull(13) ? null : $result->getString(13); displayRoleId: $result->getStringOrNull(12),
$this->aboutContent = $result->isNull(14) ? null : $result->getString(14); totpKey: $result->getStringOrNull(13),
$this->aboutParser = $result->getInteger(15); aboutContent: $result->getStringOrNull(14),
$this->signatureContent = $result->isNull(16) ? null : $result->getString(16); aboutParser: $result->getInteger(15),
$this->signatureParser = $result->getInteger(17); signatureContent: $result->getStringOrNull(16),
$this->birthdate = $result->isNull(18) ? null : $result->getString(18); signatureParser: $result->getInteger(17),
$this->backgroundSettings = $result->isNull(19) ? null : $result->getInteger(19); birthdate: $result->getStringOrNull(18),
$this->title = $result->getString(20); backgroundSettings: $result->getIntegerOrNull(19),
title: $result->getString(20),
);
} }
public function getId(): string { public function getId(): string {

View file

@ -112,7 +112,7 @@ class Users {
?bool $reverseOrder = null, ?bool $reverseOrder = null,
?array $searchQuery = null, ?array $searchQuery = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
// remove this hack when search server // remove this hack when search server
$hasSearchQuery = $searchQuery !== null; $hasSearchQuery = $searchQuery !== null;
$searchLimitResults = false; $searchLimitResults = false;
@ -211,13 +211,7 @@ class Users {
} }
$stmt->execute(); $stmt->execute();
$users = []; return $stmt->getResult()->getIterator(UserInfo::fromResult(...));
$result = $stmt->getResult();
while($result->next())
$users[] = new UserInfo($result);
return $users;
} }
public const GET_USER_ID = 0x01; public const GET_USER_ID = 0x01;
@ -283,7 +277,7 @@ class Users {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('User not found.'); throw new RuntimeException('User not found.');
return new UserInfo($result); return UserInfo::fromResult($result);
} }
public function createUser( public function createUser(

View file

@ -5,18 +5,22 @@ use Index\DateTime;
use Index\Data\IDbResult; use Index\Data\IDbResult;
class WarningInfo { class WarningInfo {
private string $id; public function __construct(
private string $userId; private string $id,
private ?string $modId; private string $userId,
private string $body; private ?string $modId,
private int $created; private string $body,
private int $created,
) {}
public function __construct(IDbResult $result) { public static function fromResult(IDbResult $result): WarningInfo {
$this->id = (string)$result->getInteger(0); return new WarningInfo(
$this->userId = (string)$result->getInteger(1); id: $result->getString(0),
$this->modId = $result->isNull(2) ? null : (string)$result->getInteger(2); userId: $result->getString(1),
$this->body = $result->getString(3); modId: $result->getStringOrNull(2),
$this->created = $result->getInteger(4); body: $result->getString(3),
created: $result->getInteger(4)
);
} }
public function getId(): string { public function getId(): string {

View file

@ -53,18 +53,14 @@ class Warnings {
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); $result = $stmt->getResult();
$count = 0;
if($result->next()) return $result->next() ? $result->getInteger(0) : 0;
$count = $result->getInteger(0);
return $count;
} }
public function getWarningsWithDefaultBacklog( public function getWarningsWithDefaultBacklog(
UserInfo|string|null $userInfo = null, UserInfo|string|null $userInfo = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
return $this->getWarnings( return $this->getWarnings(
$userInfo, $userInfo,
self::VISIBLE_BACKLOG, self::VISIBLE_BACKLOG,
@ -76,7 +72,7 @@ class Warnings {
UserInfo|string|null $userInfo = null, UserInfo|string|null $userInfo = null,
?int $backlog = null, ?int $backlog = null,
?Pagination $pagination = null ?Pagination $pagination = null
): array { ): iterable {
if($userInfo instanceof UserInfo) if($userInfo instanceof UserInfo)
$userInfo = $userInfo->getId(); $userInfo = $userInfo->getId();
@ -111,13 +107,7 @@ class Warnings {
} }
$stmt->execute(); $stmt->execute();
$result = $stmt->getResult(); return $stmt->getResult()->getIterator(WarningInfo::fromResult(...));
$warns = [];
while($result->next())
$warns[] = new WarningInfo($result);
return $warns;
} }
public function getWarning(string $warnId): WarningInfo { public function getWarning(string $warnId): WarningInfo {
@ -130,7 +120,7 @@ class Warnings {
if(!$result->next()) if(!$result->next())
throw new RuntimeException('Could not find warning info for ID $warnId.'); throw new RuntimeException('Could not find warning info for ID $warnId.');
return new WarningInfo($result); return WarningInfo::fromResult($result);
} }
public function createWarning( public function createWarning(

View file

@ -79,7 +79,7 @@
{% set show_profile_fields = not profile_is_guest and (profile_is_editing ? perms.edit_profile : profile_fields_display_values|default([]) is not empty) %} {% set show_profile_fields = not profile_is_guest and (profile_is_editing ? perms.edit_profile : profile_fields_display_values|default([]) is not empty) %}
{% set show_background_settings = profile_is_editing and perms.edit_background %} {% set show_background_settings = profile_is_editing and perms.edit_background %}
{% set show_birthdate = profile_is_editing and perms.edit_birthdate %} {% set show_birthdate = profile_is_editing and perms.edit_birthdate %}
{% set show_active_forum_info = not profile_is_guest and not profile_is_deleted and not profile_is_editing or (profile_active_category_info is defined and profile_active_category_info is not empty or profile_active_topic_info.topic_id|default(0) > 0) %} {% set show_active_forum_info = not profile_is_guest and not profile_is_deleted and not profile_is_editing and profile_active_topic_info.id|default(0) > 0 %}
{% set show_warnings = profile_warnings is defined and profile_warnings|length > 0 %} {% set show_warnings = profile_warnings is defined and profile_warnings|length > 0 %}
{% set show_sidebar = (not profile_is_banned or profile_can_edit) and (profile_is_guest or show_profile_fields or show_background_settings or show_birthdate or show_active_forum_info or show_warnings) %} {% set show_sidebar = (not profile_is_banned or profile_can_edit) and (profile_is_guest or show_profile_fields or show_background_settings or show_birthdate or show_active_forum_info or show_warnings) %}