finished laravel migration
This commit is contained in:
@@ -1,5 +1,3 @@
|
|||||||
# editorconfig.org
|
|
||||||
|
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
[*]
|
[*]
|
||||||
@@ -10,8 +8,11 @@ indent_style = space
|
|||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
[{compose.yaml,compose.*.yaml}]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[*.md]
|
[*.md]
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[compose.yaml]
|
||||||
|
indent_size = 4
|
||||||
65
.env.example
Normal file
65
.env.example
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
APP_NAME=Laravel
|
||||||
|
APP_ENV=local
|
||||||
|
APP_KEY=
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_URL=http://localhost
|
||||||
|
|
||||||
|
APP_LOCALE=en
|
||||||
|
APP_FALLBACK_LOCALE=en
|
||||||
|
APP_FAKER_LOCALE=en_US
|
||||||
|
|
||||||
|
APP_MAINTENANCE_DRIVER=file
|
||||||
|
# APP_MAINTENANCE_STORE=database
|
||||||
|
|
||||||
|
# PHP_CLI_SERVER_WORKERS=4
|
||||||
|
|
||||||
|
BCRYPT_ROUNDS=12
|
||||||
|
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
LOG_STACK=single
|
||||||
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
DB_CONNECTION=sqlite
|
||||||
|
# DB_HOST=127.0.0.1
|
||||||
|
# DB_PORT=3306
|
||||||
|
# DB_DATABASE=laravel
|
||||||
|
# DB_USERNAME=root
|
||||||
|
# DB_PASSWORD=
|
||||||
|
|
||||||
|
SESSION_DRIVER=database
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
SESSION_ENCRYPT=false
|
||||||
|
SESSION_PATH=/
|
||||||
|
SESSION_DOMAIN=null
|
||||||
|
|
||||||
|
BROADCAST_CONNECTION=log
|
||||||
|
FILESYSTEM_DISK=local
|
||||||
|
QUEUE_CONNECTION=database
|
||||||
|
|
||||||
|
CACHE_STORE=database
|
||||||
|
# CACHE_PREFIX=
|
||||||
|
|
||||||
|
MEMCACHED_HOST=127.0.0.1
|
||||||
|
|
||||||
|
REDIS_CLIENT=phpredis
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_MAILER=log
|
||||||
|
MAIL_SCHEME=null
|
||||||
|
MAIL_HOST=127.0.0.1
|
||||||
|
MAIL_PORT=2525
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_FROM_ADDRESS="hello@example.com"
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
AWS_ACCESS_KEY_ID=
|
||||||
|
AWS_SECRET_ACCESS_KEY=
|
||||||
|
AWS_DEFAULT_REGION=us-east-1
|
||||||
|
AWS_BUCKET=
|
||||||
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
|
||||||
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
*.blade.php diff=html
|
||||||
|
*.css diff=css
|
||||||
|
*.html diff=html
|
||||||
|
*.md diff=markdown
|
||||||
|
*.php diff=php
|
||||||
|
|
||||||
|
/.github export-ignore
|
||||||
|
CHANGELOG.md export-ignore
|
||||||
|
.styleci.yml export-ignore
|
||||||
37
.gitignore
vendored
37
.gitignore
vendored
@@ -1,9 +1,28 @@
|
|||||||
.idea/
|
*.log
|
||||||
node_modules/
|
.DS_Store
|
||||||
frontend/node_modules/
|
.env
|
||||||
frontend/dist/
|
.env.backup
|
||||||
api/var/
|
.env.production
|
||||||
api/vendor/
|
.env.*.local
|
||||||
api/public/app/
|
.phpactor.json
|
||||||
api/.env.local
|
.phpunit.result.cache
|
||||||
api/.env.*.local
|
/.fleet
|
||||||
|
/.idea
|
||||||
|
/.nova
|
||||||
|
/.phpunit.cache
|
||||||
|
/.vscode
|
||||||
|
/.zed
|
||||||
|
/.phpstorm.meta.php
|
||||||
|
/_ide_helper.php
|
||||||
|
/_ide_helper_models.php
|
||||||
|
/auth.json
|
||||||
|
/node_modules
|
||||||
|
/public/build
|
||||||
|
/public/hot
|
||||||
|
/public/storage
|
||||||
|
/storage/*.key
|
||||||
|
/storage/pail
|
||||||
|
/vendor
|
||||||
|
Homestead.json
|
||||||
|
Homestead.yaml
|
||||||
|
Thumbs.db
|
||||||
|
|||||||
13
CHANGELOG.md
13
CHANGELOG.md
@@ -22,3 +22,16 @@
|
|||||||
- Improved ACP drag-and-drop hover reordering and visual drop target feedback.
|
- Improved ACP drag-and-drop hover reordering and visual drop target feedback.
|
||||||
- Hardened ACP access so admin tools require authentication.
|
- Hardened ACP access so admin tools require authentication.
|
||||||
- Updated the home page to render the forum tree with ACP-style rows and icons.
|
- Updated the home page to render the forum tree with ACP-style rows and icons.
|
||||||
|
|
||||||
|
## 2025-12-26
|
||||||
|
- Replaced the Symfony backend with a fresh Laravel app in `api/`.
|
||||||
|
- Added Fortify + Sanctum, API routes, and controllers for forums/threads/posts/settings/version.
|
||||||
|
- Added Laravel migrations for forums, threads, posts, and settings (seeded with version/build/accent).
|
||||||
|
- Added Laravel i18n endpoint backed by JSON translation files.
|
||||||
|
- Updated frontend auth/register flow to work with Laravel tokens.
|
||||||
|
|
||||||
|
## 2025-12-29
|
||||||
|
- Merged the React app into the Laravel codebase under `resources/js`.
|
||||||
|
- Moved the Laravel app to the repo root and removed the separate `api/` and `frontend/` folders.
|
||||||
|
- Serve the SPA shell via Blade with Vite-managed React assets.
|
||||||
|
- Dropped Tailwind tooling to keep the frontend Bootstrap-only.
|
||||||
|
|||||||
59
README.md
Normal file
59
README.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## About Laravel
|
||||||
|
|
||||||
|
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
|
||||||
|
|
||||||
|
- [Simple, fast routing engine](https://laravel.com/docs/routing).
|
||||||
|
- [Powerful dependency injection container](https://laravel.com/docs/container).
|
||||||
|
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
|
||||||
|
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
|
||||||
|
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
|
||||||
|
- [Robust background job processing](https://laravel.com/docs/queues).
|
||||||
|
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
|
||||||
|
|
||||||
|
Laravel is accessible, powerful, and provides tools required for large, robust applications.
|
||||||
|
|
||||||
|
## Learning Laravel
|
||||||
|
|
||||||
|
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework. You can also check out [Laravel Learn](https://laravel.com/learn), where you will be guided through building a modern Laravel application.
|
||||||
|
|
||||||
|
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
|
||||||
|
|
||||||
|
## Laravel Sponsors
|
||||||
|
|
||||||
|
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com).
|
||||||
|
|
||||||
|
### Premium Partners
|
||||||
|
|
||||||
|
- **[Vehikl](https://vehikl.com)**
|
||||||
|
- **[Tighten Co.](https://tighten.co)**
|
||||||
|
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
|
||||||
|
- **[64 Robots](https://64robots.com)**
|
||||||
|
- **[Curotec](https://www.curotec.com/services/technologies/laravel)**
|
||||||
|
- **[DevSquad](https://devsquad.com/hire-laravel-developers)**
|
||||||
|
- **[Redberry](https://redberry.international/laravel-development)**
|
||||||
|
- **[Active Logic](https://activelogic.com)**
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
|
||||||
|
|
||||||
|
## Security Vulnerabilities
|
||||||
|
|
||||||
|
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
|
||||||
35
api/.env
35
api/.env
@@ -1,35 +0,0 @@
|
|||||||
# In all environments, the following files are loaded if they exist,
|
|
||||||
# the latter taking precedence over the former:
|
|
||||||
#
|
|
||||||
# * .env contains default values for the environment variables needed by the app
|
|
||||||
# * .env.local uncommitted file with local overrides
|
|
||||||
# * .env.$APP_ENV committed environment-specific defaults
|
|
||||||
# * .env.$APP_ENV.local uncommitted environment-specific overrides
|
|
||||||
#
|
|
||||||
# Real environment variables win over .env files.
|
|
||||||
#
|
|
||||||
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
|
|
||||||
# https://symfony.com/doc/current/configuration/secrets.html
|
|
||||||
#
|
|
||||||
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
|
|
||||||
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
|
|
||||||
|
|
||||||
###> symfony/framework-bundle ###
|
|
||||||
APP_ENV=dev
|
|
||||||
APP_SECRET=
|
|
||||||
APP_SHARE_DIR=var/share
|
|
||||||
###< symfony/framework-bundle ###
|
|
||||||
|
|
||||||
###> symfony/routing ###
|
|
||||||
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
|
|
||||||
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
|
|
||||||
DEFAULT_URI=http://localhost
|
|
||||||
###< symfony/routing ###
|
|
||||||
|
|
||||||
###> doctrine/doctrine-bundle ###
|
|
||||||
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
|
|
||||||
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
|
|
||||||
#
|
|
||||||
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data_%kernel.environment%.db"
|
|
||||||
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/speedbb?serverVersion=8.0.32&charset=utf8mb4"
|
|
||||||
###< doctrine/doctrine-bundle ###
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
|
|
||||||
###> symfony/framework-bundle ###
|
|
||||||
APP_SECRET=7944fa8dd76a206ea3e7e16b9276029c
|
|
||||||
###< symfony/framework-bundle ###
|
|
||||||
14
api/.gitignore
vendored
14
api/.gitignore
vendored
@@ -1,14 +0,0 @@
|
|||||||
|
|
||||||
###> symfony/framework-bundle ###
|
|
||||||
/.env.local
|
|
||||||
/.env.local.php
|
|
||||||
/.env.*.local
|
|
||||||
/config/secrets/prod/prod.decrypt.private.php
|
|
||||||
/public/bundles/
|
|
||||||
/var/
|
|
||||||
/vendor/
|
|
||||||
###< symfony/framework-bundle ###
|
|
||||||
|
|
||||||
###> lexik/jwt-authentication-bundle ###
|
|
||||||
/config/jwt/*.pem
|
|
||||||
###< lexik/jwt-authentication-bundle ###
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
use App\Kernel;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
|
||||||
|
|
||||||
if (!is_dir(dirname(__DIR__).'/vendor')) {
|
|
||||||
throw new LogicException('Dependencies are missing. Try running "composer install".');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
|
|
||||||
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
|
|
||||||
}
|
|
||||||
|
|
||||||
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
|
|
||||||
|
|
||||||
return function (array $context) {
|
|
||||||
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
|
|
||||||
|
|
||||||
return new Application($kernel);
|
|
||||||
};
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
|
|
||||||
services:
|
|
||||||
###> doctrine/doctrine-bundle ###
|
|
||||||
database:
|
|
||||||
ports:
|
|
||||||
- "5432"
|
|
||||||
###< doctrine/doctrine-bundle ###
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
services:
|
|
||||||
###> doctrine/doctrine-bundle ###
|
|
||||||
database:
|
|
||||||
image: postgres:${POSTGRES_VERSION:-16}-alpine
|
|
||||||
environment:
|
|
||||||
POSTGRES_DB: ${POSTGRES_DB:-app}
|
|
||||||
# You should definitely change the password in production
|
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-!ChangeMe!}
|
|
||||||
POSTGRES_USER: ${POSTGRES_USER:-app}
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "pg_isready", "-d", "${POSTGRES_DB:-app}", "-U", "${POSTGRES_USER:-app}"]
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
start_period: 60s
|
|
||||||
volumes:
|
|
||||||
- database_data:/var/lib/postgresql/data:rw
|
|
||||||
# You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data!
|
|
||||||
# - ./docker/db/data:/var/lib/postgresql/data:rw
|
|
||||||
###< doctrine/doctrine-bundle ###
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
###> doctrine/doctrine-bundle ###
|
|
||||||
database_data:
|
|
||||||
###< doctrine/doctrine-bundle ###
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "project",
|
|
||||||
"version": "25.00.1",
|
|
||||||
"license": "proprietary",
|
|
||||||
"minimum-stability": "stable",
|
|
||||||
"prefer-stable": true,
|
|
||||||
"require": {
|
|
||||||
"php": ">=8.4",
|
|
||||||
"ext-ctype": "*",
|
|
||||||
"ext-iconv": "*",
|
|
||||||
"api-platform/doctrine-orm": "^4.2",
|
|
||||||
"api-platform/symfony": "^4.2",
|
|
||||||
"doctrine/doctrine-bundle": "^3.2",
|
|
||||||
"doctrine/doctrine-migrations-bundle": "^4.0",
|
|
||||||
"doctrine/orm": "^3.6",
|
|
||||||
"lexik/jwt-authentication-bundle": "^3.2",
|
|
||||||
"phpdocumentor/reflection-docblock": "^5.6",
|
|
||||||
"phpstan/phpdoc-parser": "^2.3",
|
|
||||||
"symfony/apache-pack": "*",
|
|
||||||
"symfony/asset": "8.0.*",
|
|
||||||
"symfony/console": "8.0.*",
|
|
||||||
"symfony/dotenv": "8.0.*",
|
|
||||||
"symfony/expression-language": "8.0.*",
|
|
||||||
"symfony/flex": "^2",
|
|
||||||
"symfony/framework-bundle": "8.0.*",
|
|
||||||
"symfony/property-access": "8.0.*",
|
|
||||||
"symfony/property-info": "8.0.*",
|
|
||||||
"symfony/runtime": "8.0.*",
|
|
||||||
"symfony/security-bundle": "8.0.*",
|
|
||||||
"symfony/serializer": "8.0.*",
|
|
||||||
"symfony/translation": "8.0.*",
|
|
||||||
"symfony/twig-bundle": "8.0.*",
|
|
||||||
"symfony/validator": "8.0.*",
|
|
||||||
"symfony/yaml": "8.0.*"
|
|
||||||
},
|
|
||||||
"config": {
|
|
||||||
"allow-plugins": {
|
|
||||||
"php-http/discovery": true,
|
|
||||||
"symfony/flex": true,
|
|
||||||
"symfony/runtime": true
|
|
||||||
},
|
|
||||||
"bump-after-update": true,
|
|
||||||
"sort-packages": true
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"App\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload-dev": {
|
|
||||||
"psr-4": {
|
|
||||||
"App\\Tests\\": "tests/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"replace": {
|
|
||||||
"symfony/polyfill-ctype": "*",
|
|
||||||
"symfony/polyfill-iconv": "*",
|
|
||||||
"symfony/polyfill-php72": "*",
|
|
||||||
"symfony/polyfill-php73": "*",
|
|
||||||
"symfony/polyfill-php74": "*",
|
|
||||||
"symfony/polyfill-php80": "*",
|
|
||||||
"symfony/polyfill-php81": "*",
|
|
||||||
"symfony/polyfill-php82": "*",
|
|
||||||
"symfony/polyfill-php83": "*",
|
|
||||||
"symfony/polyfill-php84": "*"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"auto-scripts": {
|
|
||||||
"cache:clear": "symfony-cmd",
|
|
||||||
"assets:install %PUBLIC_DIR%": "symfony-cmd"
|
|
||||||
},
|
|
||||||
"post-install-cmd": [
|
|
||||||
"@auto-scripts"
|
|
||||||
],
|
|
||||||
"post-update-cmd": [
|
|
||||||
"@auto-scripts"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"conflict": {
|
|
||||||
"symfony/symfony": "*"
|
|
||||||
},
|
|
||||||
"extra": {
|
|
||||||
"speedbb": {
|
|
||||||
"build": 3
|
|
||||||
},
|
|
||||||
"symfony": {
|
|
||||||
"allow-contrib": false,
|
|
||||||
"require": "8.0.*"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
7418
api/composer.lock
generated
7418
api/composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,11 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
|
||||||
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
|
|
||||||
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
|
||||||
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
|
|
||||||
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
|
|
||||||
ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
|
|
||||||
Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
|
|
||||||
];
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
api_platform:
|
|
||||||
title: speedBB API
|
|
||||||
version: 1.0.0
|
|
||||||
formats:
|
|
||||||
json: ['application/json']
|
|
||||||
jsonld: ['application/ld+json']
|
|
||||||
defaults:
|
|
||||||
stateless: true
|
|
||||||
cache_headers:
|
|
||||||
vary: ['Content-Type', 'Authorization', 'Origin']
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
framework:
|
|
||||||
cache:
|
|
||||||
# Unique name of your app: used to compute stable namespaces for cache keys.
|
|
||||||
#prefix_seed: your_vendor_name/app_name
|
|
||||||
|
|
||||||
# The "app" cache stores to the filesystem by default.
|
|
||||||
# The data in this cache should persist between deploys.
|
|
||||||
# Other options include:
|
|
||||||
|
|
||||||
# Redis
|
|
||||||
#app: cache.adapter.redis
|
|
||||||
#default_redis_provider: redis://localhost
|
|
||||||
|
|
||||||
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
|
|
||||||
#app: cache.adapter.apcu
|
|
||||||
|
|
||||||
# Namespaced pools use the above "app" backend by default
|
|
||||||
#pools:
|
|
||||||
#my.dedicated.cache: null
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
doctrine:
|
|
||||||
dbal:
|
|
||||||
url: '%env(resolve:DATABASE_URL)%'
|
|
||||||
|
|
||||||
# IMPORTANT: You MUST configure your server version,
|
|
||||||
# either here or in the DATABASE_URL env var (see .env file)
|
|
||||||
#server_version: '16'
|
|
||||||
|
|
||||||
profiling_collect_backtrace: '%kernel.debug%'
|
|
||||||
orm:
|
|
||||||
validate_xml_mapping: true
|
|
||||||
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
|
|
||||||
auto_mapping: true
|
|
||||||
mappings:
|
|
||||||
App:
|
|
||||||
type: attribute
|
|
||||||
is_bundle: false
|
|
||||||
dir: '%kernel.project_dir%/src/Entity'
|
|
||||||
prefix: 'App\Entity'
|
|
||||||
alias: App
|
|
||||||
controller_resolver:
|
|
||||||
auto_mapping: false
|
|
||||||
|
|
||||||
when@test:
|
|
||||||
doctrine:
|
|
||||||
dbal:
|
|
||||||
# "TEST_TOKEN" is typically set by ParaTest
|
|
||||||
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
|
|
||||||
|
|
||||||
when@prod:
|
|
||||||
doctrine:
|
|
||||||
orm:
|
|
||||||
query_cache_driver:
|
|
||||||
type: pool
|
|
||||||
pool: doctrine.system_cache_pool
|
|
||||||
result_cache_driver:
|
|
||||||
type: pool
|
|
||||||
pool: doctrine.result_cache_pool
|
|
||||||
|
|
||||||
framework:
|
|
||||||
cache:
|
|
||||||
pools:
|
|
||||||
doctrine.result_cache_pool:
|
|
||||||
adapter: cache.app
|
|
||||||
doctrine.system_cache_pool:
|
|
||||||
adapter: cache.system
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
doctrine_migrations:
|
|
||||||
migrations_paths:
|
|
||||||
# namespace is arbitrary but should be different from App\Migrations
|
|
||||||
# as migrations classes should NOT be autoloaded
|
|
||||||
'DoctrineMigrations': '%kernel.project_dir%/migrations'
|
|
||||||
enable_profiler: false
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# see https://symfony.com/doc/current/reference/configuration/framework.html
|
|
||||||
framework:
|
|
||||||
secret: '%env(APP_SECRET)%'
|
|
||||||
|
|
||||||
# Note that the session will be started ONLY if you read or write from it.
|
|
||||||
session: true
|
|
||||||
|
|
||||||
serializer:
|
|
||||||
enabled: true
|
|
||||||
|
|
||||||
#esi: true
|
|
||||||
#fragments: true
|
|
||||||
|
|
||||||
when@test:
|
|
||||||
framework:
|
|
||||||
test: true
|
|
||||||
session:
|
|
||||||
storage_factory_id: session.storage.factory.mock_file
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
lexik_jwt_authentication:
|
|
||||||
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
|
|
||||||
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
|
|
||||||
pass_phrase: '%env(JWT_PASSPHRASE)%'
|
|
||||||
token_ttl: 86400
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
framework:
|
|
||||||
property_info:
|
|
||||||
with_constructor_extractor: true
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
framework:
|
|
||||||
router:
|
|
||||||
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
|
|
||||||
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
|
|
||||||
default_uri: '%env(DEFAULT_URI)%'
|
|
||||||
|
|
||||||
when@prod:
|
|
||||||
framework:
|
|
||||||
router:
|
|
||||||
strict_requirements: null
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
security:
|
|
||||||
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
|
||||||
password_hashers:
|
|
||||||
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
|
|
||||||
|
|
||||||
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
|
|
||||||
providers:
|
|
||||||
app_user_provider:
|
|
||||||
entity:
|
|
||||||
class: App\Entity\User
|
|
||||||
property: email
|
|
||||||
|
|
||||||
firewalls:
|
|
||||||
dev:
|
|
||||||
# Ensure dev tools and static assets are always allowed
|
|
||||||
pattern: ^/(_profiler|_wdt|assets|build)/
|
|
||||||
security: false
|
|
||||||
login:
|
|
||||||
pattern: ^/api/login
|
|
||||||
stateless: true
|
|
||||||
provider: app_user_provider
|
|
||||||
json_login:
|
|
||||||
check_path: /api/login
|
|
||||||
username_path: email
|
|
||||||
password_path: password
|
|
||||||
success_handler: lexik_jwt_authentication.handler.authentication_success
|
|
||||||
failure_handler: lexik_jwt_authentication.handler.authentication_failure
|
|
||||||
main:
|
|
||||||
pattern: ^/api
|
|
||||||
lazy: true
|
|
||||||
stateless: true
|
|
||||||
provider: app_user_provider
|
|
||||||
jwt: ~
|
|
||||||
|
|
||||||
# Activate different ways to authenticate:
|
|
||||||
# https://symfony.com/doc/current/security.html#the-firewall
|
|
||||||
|
|
||||||
# https://symfony.com/doc/current/security/impersonating_user.html
|
|
||||||
# switch_user: true
|
|
||||||
|
|
||||||
# Note: Only the *first* matching rule is applied
|
|
||||||
access_control:
|
|
||||||
- { path: ^/api/login, roles: PUBLIC_ACCESS }
|
|
||||||
- { path: ^/api, roles: PUBLIC_ACCESS }
|
|
||||||
|
|
||||||
when@test:
|
|
||||||
security:
|
|
||||||
password_hashers:
|
|
||||||
# Password hashers are resource-intensive by design to ensure security.
|
|
||||||
# In tests, it's safe to reduce their cost to improve performance.
|
|
||||||
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
|
|
||||||
algorithm: auto
|
|
||||||
cost: 4 # Lowest possible value for bcrypt
|
|
||||||
time_cost: 3 # Lowest possible value for argon
|
|
||||||
memory_cost: 10 # Lowest possible value for argon
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
framework:
|
|
||||||
default_locale: en
|
|
||||||
translator:
|
|
||||||
default_path: '%kernel.project_dir%/translations'
|
|
||||||
providers:
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
twig:
|
|
||||||
file_name_pattern: '*.twig'
|
|
||||||
|
|
||||||
when@test:
|
|
||||||
twig:
|
|
||||||
strict_variables: true
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
framework:
|
|
||||||
validation:
|
|
||||||
# Enables validator auto-mapping support.
|
|
||||||
# For instance, basic validation constraints will be inferred from Doctrine's metadata.
|
|
||||||
#auto_mapping:
|
|
||||||
# App\Entity\: []
|
|
||||||
|
|
||||||
when@test:
|
|
||||||
framework:
|
|
||||||
validation:
|
|
||||||
not_compromised_password: false
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) {
|
|
||||||
require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php';
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +0,0 @@
|
|||||||
# yaml-language-server: $schema=../vendor/symfony/routing/Loader/schema/routing.schema.json
|
|
||||||
|
|
||||||
# This file is the entry point to configure the routes of your app.
|
|
||||||
# Methods with the #[Route] attribute are automatically imported.
|
|
||||||
# See also https://symfony.com/doc/current/routing.html
|
|
||||||
|
|
||||||
# To list all registered routes, run the following command:
|
|
||||||
# bin/console debug:router
|
|
||||||
|
|
||||||
controllers:
|
|
||||||
resource: routing.controllers
|
|
||||||
|
|
||||||
api_login:
|
|
||||||
path: /api/login
|
|
||||||
methods: [POST]
|
|
||||||
controller: lexik_jwt_authentication.controller.authentication
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
api_platform:
|
|
||||||
resource: .
|
|
||||||
type: api_platform
|
|
||||||
prefix: /api
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
when@dev:
|
|
||||||
_errors:
|
|
||||||
resource: '@FrameworkBundle/Resources/config/routing/errors.php'
|
|
||||||
prefix: /_error
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
_security_logout:
|
|
||||||
resource: security.route_loader.logout
|
|
||||||
type: service
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# yaml-language-server: $schema=../vendor/symfony/dependency-injection/Loader/schema/services.schema.json
|
|
||||||
|
|
||||||
# This file is the entry point to configure your own services.
|
|
||||||
# Files in the packages/ subdirectory configure your dependencies.
|
|
||||||
# See also https://symfony.com/doc/current/service_container/import.html
|
|
||||||
|
|
||||||
# Put parameters here that don't need to change on each machine where the app is deployed
|
|
||||||
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
|
|
||||||
parameters:
|
|
||||||
|
|
||||||
services:
|
|
||||||
# default configuration for services in *this* file
|
|
||||||
_defaults:
|
|
||||||
autowire: true # Automatically injects dependencies in your services.
|
|
||||||
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
|
|
||||||
|
|
||||||
# makes classes in src/ available to be used as services
|
|
||||||
# this creates a service per class whose id is the fully-qualified class name
|
|
||||||
App\:
|
|
||||||
resource: '../src/'
|
|
||||||
|
|
||||||
# add more service definitions when explicit configuration is needed
|
|
||||||
# please note that last definitions always *replace* previous ones
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace DoctrineMigrations;
|
|
||||||
|
|
||||||
use Doctrine\DBAL\Schema\Schema;
|
|
||||||
use Doctrine\Migrations\AbstractMigration;
|
|
||||||
|
|
||||||
final class Version20251224115331 extends AbstractMigration
|
|
||||||
{
|
|
||||||
public function getDescription(): string
|
|
||||||
{
|
|
||||||
return 'Initial schema (executed previously).';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function up(Schema $schema): void
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down(Schema $schema): void
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace DoctrineMigrations;
|
|
||||||
|
|
||||||
use Doctrine\DBAL\Schema\Schema;
|
|
||||||
use Doctrine\Migrations\AbstractMigration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Auto-generated Migration: Please modify to your needs!
|
|
||||||
*/
|
|
||||||
final class Version20251224120510 extends AbstractMigration
|
|
||||||
{
|
|
||||||
public function getDescription(): string
|
|
||||||
{
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function up(Schema $schema): void
|
|
||||||
{
|
|
||||||
// this up() migration is auto-generated, please modify it to your needs
|
|
||||||
$this->addSql('CREATE TABLE forum (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(100) NOT NULL, description LONGTEXT DEFAULT NULL, type VARCHAR(20) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, parent_id INT DEFAULT NULL, INDEX IDX_852BBECD727ACA70 (parent_id), PRIMARY KEY (id)) DEFAULT CHARACTER SET utf8mb4');
|
|
||||||
$this->addSql('ALTER TABLE forum ADD CONSTRAINT FK_852BBECD727ACA70 FOREIGN KEY (parent_id) REFERENCES forum (id)');
|
|
||||||
$this->addSql('ALTER TABLE thread DROP FOREIGN KEY `FK_31204C8312469DE2`');
|
|
||||||
$this->addSql('DROP INDEX IDX_31204C8312469DE2 ON thread');
|
|
||||||
$this->addSql('INSERT INTO forum (id, name, description, type, created_at, updated_at) SELECT id, name, description, \'forum\', created_at, updated_at FROM category');
|
|
||||||
$this->addSql('ALTER TABLE thread CHANGE category_id forum_id INT NOT NULL');
|
|
||||||
$this->addSql('ALTER TABLE thread ADD CONSTRAINT FK_31204C8329CCBAD0 FOREIGN KEY (forum_id) REFERENCES forum (id)');
|
|
||||||
$this->addSql('CREATE INDEX IDX_31204C8329CCBAD0 ON thread (forum_id)');
|
|
||||||
$this->addSql('DROP TABLE category');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down(Schema $schema): void
|
|
||||||
{
|
|
||||||
// this down() migration is auto-generated, please modify it to your needs
|
|
||||||
$this->addSql('CREATE TABLE category (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(100) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_general_ci`, description LONGTEXT CHARACTER SET utf8mb4 DEFAULT NULL COLLATE `utf8mb4_general_ci`, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, PRIMARY KEY (id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_general_ci` ENGINE = InnoDB COMMENT = \'\' ');
|
|
||||||
$this->addSql('ALTER TABLE forum DROP FOREIGN KEY FK_852BBECD727ACA70');
|
|
||||||
$this->addSql('DROP TABLE forum');
|
|
||||||
$this->addSql('ALTER TABLE thread DROP FOREIGN KEY FK_31204C8329CCBAD0');
|
|
||||||
$this->addSql('DROP INDEX IDX_31204C8329CCBAD0 ON thread');
|
|
||||||
$this->addSql('ALTER TABLE thread CHANGE forum_id category_id INT NOT NULL');
|
|
||||||
$this->addSql('ALTER TABLE thread ADD CONSTRAINT `FK_31204C8312469DE2` FOREIGN KEY (category_id) REFERENCES category (id)');
|
|
||||||
$this->addSql('CREATE INDEX IDX_31204C8312469DE2 ON thread (category_id)');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace DoctrineMigrations;
|
|
||||||
|
|
||||||
use Doctrine\DBAL\Schema\Schema;
|
|
||||||
use Doctrine\Migrations\AbstractMigration;
|
|
||||||
|
|
||||||
final class Version20251224154500 extends AbstractMigration
|
|
||||||
{
|
|
||||||
public function getDescription(): string
|
|
||||||
{
|
|
||||||
return 'Add forum position for per-parent ordering.';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function up(Schema $schema): void
|
|
||||||
{
|
|
||||||
$this->addSql('ALTER TABLE forum ADD position INT NOT NULL');
|
|
||||||
$this->addSql('UPDATE forum SET position = id');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down(Schema $schema): void
|
|
||||||
{
|
|
||||||
$this->addSql('ALTER TABLE forum DROP position');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace DoctrineMigrations;
|
|
||||||
|
|
||||||
use Doctrine\DBAL\Schema\Schema;
|
|
||||||
use Doctrine\Migrations\AbstractMigration;
|
|
||||||
|
|
||||||
final class Version20251224184500 extends AbstractMigration
|
|
||||||
{
|
|
||||||
public function getDescription(): string
|
|
||||||
{
|
|
||||||
return 'Add settings table with version and build metadata.';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function up(Schema $schema): void
|
|
||||||
{
|
|
||||||
$this->addSql('CREATE TABLE settings (id INT AUTO_INCREMENT NOT NULL, version VARCHAR(20) NOT NULL, build INT NOT NULL, PRIMARY KEY(id))');
|
|
||||||
$this->addSql("INSERT INTO settings (id, version, build) VALUES (1, '25.00.1', 3)");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down(Schema $schema): void
|
|
||||||
{
|
|
||||||
$this->addSql('DROP TABLE settings');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace DoctrineMigrations;
|
|
||||||
|
|
||||||
use Doctrine\DBAL\Schema\Schema;
|
|
||||||
use Doctrine\Migrations\AbstractMigration;
|
|
||||||
|
|
||||||
final class Version20251224191500 extends AbstractMigration
|
|
||||||
{
|
|
||||||
public function getDescription(): string
|
|
||||||
{
|
|
||||||
return 'Convert settings table to key/value rows for version/build.';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function up(Schema $schema): void
|
|
||||||
{
|
|
||||||
$this->addSql('CREATE TABLE settings_new (id INT AUTO_INCREMENT NOT NULL, `key` VARCHAR(100) NOT NULL, value LONGTEXT NOT NULL, UNIQUE INDEX UNIQ_SETTINGS_KEY (`key`), PRIMARY KEY(id))');
|
|
||||||
$this->addSql("INSERT INTO settings_new (`key`, value) SELECT 'version', version FROM settings LIMIT 1");
|
|
||||||
$this->addSql("INSERT INTO settings_new (`key`, value) SELECT 'build', CAST(build AS CHAR) FROM settings LIMIT 1");
|
|
||||||
$this->addSql('DROP TABLE settings');
|
|
||||||
$this->addSql('RENAME TABLE settings_new TO settings');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down(Schema $schema): void
|
|
||||||
{
|
|
||||||
$this->addSql('CREATE TABLE settings_old (id INT AUTO_INCREMENT NOT NULL, version VARCHAR(20) NOT NULL, build INT NOT NULL, PRIMARY KEY(id))');
|
|
||||||
$this->addSql("INSERT INTO settings_old (id, version, build) VALUES (1, (SELECT value FROM settings WHERE `key` = 'version' LIMIT 1), CAST((SELECT value FROM settings WHERE `key` = 'build' LIMIT 1) AS UNSIGNED))");
|
|
||||||
$this->addSql('DROP TABLE settings');
|
|
||||||
$this->addSql('RENAME TABLE settings_old TO settings');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace DoctrineMigrations;
|
|
||||||
|
|
||||||
use Doctrine\DBAL\Schema\Schema;
|
|
||||||
use Doctrine\Migrations\AbstractMigration;
|
|
||||||
|
|
||||||
final class Version20251224193000 extends AbstractMigration
|
|
||||||
{
|
|
||||||
public function getDescription(): string
|
|
||||||
{
|
|
||||||
return 'Add indexes for forum parent ordering and type filters.';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function up(Schema $schema): void
|
|
||||||
{
|
|
||||||
$this->addSql('CREATE INDEX idx_forum_parent_position ON forum (parent_id, position)');
|
|
||||||
$this->addSql('CREATE INDEX idx_forum_type ON forum (type)');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down(Schema $schema): void
|
|
||||||
{
|
|
||||||
$this->addSql('DROP INDEX idx_forum_parent_position ON forum');
|
|
||||||
$this->addSql('DROP INDEX idx_forum_type ON forum');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace DoctrineMigrations;
|
|
||||||
|
|
||||||
use Doctrine\DBAL\Schema\Schema;
|
|
||||||
use Doctrine\Migrations\AbstractMigration;
|
|
||||||
|
|
||||||
final class Version20251224194000 extends AbstractMigration
|
|
||||||
{
|
|
||||||
public function getDescription(): string
|
|
||||||
{
|
|
||||||
return 'Add accent color setting.';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function up(Schema $schema): void
|
|
||||||
{
|
|
||||||
$this->addSql("INSERT IGNORE INTO settings (`key`, value) VALUES ('accent_color', '#f29b3f')");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down(Schema $schema): void
|
|
||||||
{
|
|
||||||
$this->addSql("DELETE FROM settings WHERE `key` = 'accent_color'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<IfModule mod_rewrite.c>
|
|
||||||
RewriteEngine On
|
|
||||||
|
|
||||||
RewriteCond %{HTTP:Authorization} .
|
|
||||||
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
|
||||||
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
|
||||||
|
|
||||||
RewriteCond %{REQUEST_FILENAME} -f
|
|
||||||
RewriteRule ^ - [L]
|
|
||||||
|
|
||||||
RewriteCond %{REQUEST_FILENAME} -d
|
|
||||||
RewriteRule ^ - [L]
|
|
||||||
|
|
||||||
RewriteRule ^ index.php [L]
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule mod_setenvif.c>
|
|
||||||
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
|
|
||||||
</IfModule>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use App\Kernel;
|
|
||||||
|
|
||||||
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
|
|
||||||
|
|
||||||
return function (array $context) {
|
|
||||||
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
|
|
||||||
};
|
|
||||||
0
api/src/ApiResource/.gitignore
vendored
0
api/src/ApiResource/.gitignore
vendored
0
api/src/Controller/.gitignore
vendored
0
api/src/Controller/.gitignore
vendored
@@ -1,77 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Controller;
|
|
||||||
|
|
||||||
use App\Entity\Forum;
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
use Symfony\Bundle\SecurityBundle\Security;
|
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
|
||||||
|
|
||||||
class ForumReorderController
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private EntityManagerInterface $entityManager,
|
|
||||||
private Security $security
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route('/api/forums/reorder', name: 'api_forums_reorder', methods: ['POST'])]
|
|
||||||
public function __invoke(Request $request): JsonResponse
|
|
||||||
{
|
|
||||||
if (!$this->security->isGranted('ROLE_ADMIN')) {
|
|
||||||
return new JsonResponse(['message' => 'Forbidden'], JsonResponse::HTTP_FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
$payload = json_decode($request->getContent(), true);
|
|
||||||
$orderedIds = $payload['orderedIds'] ?? null;
|
|
||||||
|
|
||||||
if (!is_array($orderedIds) || $orderedIds === []) {
|
|
||||||
return new JsonResponse(['message' => 'orderedIds must be a non-empty array.'], JsonResponse::HTTP_BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
$parentId = $payload['parentId'] ?? null;
|
|
||||||
$parent = null;
|
|
||||||
if (null !== $parentId) {
|
|
||||||
$parent = $this->entityManager->getRepository(Forum::class)->find($parentId);
|
|
||||||
if (!$parent instanceof Forum) {
|
|
||||||
return new JsonResponse(['message' => 'Parent not found.'], JsonResponse::HTTP_BAD_REQUEST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$forums = $this->entityManager->getRepository(Forum::class)
|
|
||||||
->findBy(['id' => $orderedIds]);
|
|
||||||
|
|
||||||
if (count($forums) !== count($orderedIds)) {
|
|
||||||
return new JsonResponse(['message' => 'Some forums were not found.'], JsonResponse::HTTP_BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
$forumsById = [];
|
|
||||||
foreach ($forums as $forum) {
|
|
||||||
$forumsById[(string) $forum->getId()] = $forum;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($orderedIds as $id) {
|
|
||||||
if (!isset($forumsById[(string) $id])) {
|
|
||||||
return new JsonResponse(['message' => 'Invalid forum list.'], JsonResponse::HTTP_BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
$forum = $forumsById[(string) $id];
|
|
||||||
$forumParent = $forum->getParent();
|
|
||||||
if (($parent === null && $forumParent !== null) || ($parent !== null && $forumParent?->getId() !== $parent->getId())) {
|
|
||||||
return new JsonResponse(['message' => 'Forums must share the same parent.'], JsonResponse::HTTP_BAD_REQUEST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$position = 1;
|
|
||||||
foreach ($orderedIds as $id) {
|
|
||||||
$forumsById[(string) $id]->setPosition($position);
|
|
||||||
$position++;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->entityManager->flush();
|
|
||||||
|
|
||||||
return new JsonResponse(['status' => 'ok']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Controller;
|
|
||||||
|
|
||||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
|
||||||
|
|
||||||
class FrontendController
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
#[Autowire('%kernel.project_dir%')]
|
|
||||||
private string $projectDir
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route('/', name: 'frontend_index')]
|
|
||||||
#[Route('/{path}', name: 'frontend_spa', requirements: ['path' => '^(?!api|app|_profiler|_wdt|bundles).+'])]
|
|
||||||
public function __invoke(): Response
|
|
||||||
{
|
|
||||||
$indexPath = $this->projectDir . '/public/app/index.html';
|
|
||||||
|
|
||||||
if (!is_file($indexPath)) {
|
|
||||||
return new Response(
|
|
||||||
'Frontend build not found. Run `npm run build` in the frontend folder.',
|
|
||||||
Response::HTTP_INTERNAL_SERVER_ERROR
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Response(file_get_contents($indexPath), Response::HTTP_OK, [
|
|
||||||
'Content-Type' => 'text/html; charset=UTF-8',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Controller;
|
|
||||||
|
|
||||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
||||||
|
|
||||||
class I18nController
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private TranslatorInterface $translator,
|
|
||||||
#[Autowire('%kernel.default_locale%')]
|
|
||||||
private string $defaultLocale
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Route(
|
|
||||||
'/api/i18n/{locale}',
|
|
||||||
name: 'api_i18n',
|
|
||||||
methods: ['GET'],
|
|
||||||
requirements: ['locale' => '[A-Za-z0-9_-]+']
|
|
||||||
)]
|
|
||||||
public function __invoke(string $locale): JsonResponse
|
|
||||||
{
|
|
||||||
$messages = $this->getMessagesForLocale($locale);
|
|
||||||
|
|
||||||
if (!$messages && $locale !== $this->defaultLocale) {
|
|
||||||
$messages = $this->getMessagesForLocale($this->defaultLocale);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JsonResponse($messages);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getMessagesForLocale(string $locale): array
|
|
||||||
{
|
|
||||||
$catalogue = $this->translator->getCatalogue($locale);
|
|
||||||
$messages = $catalogue->all('messages');
|
|
||||||
|
|
||||||
$fallback = $catalogue->getFallbackCatalogue();
|
|
||||||
while ($fallback) {
|
|
||||||
foreach ($fallback->all('messages') as $key => $value) {
|
|
||||||
if (!array_key_exists($key, $messages)) {
|
|
||||||
$messages[$key] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$fallback = $fallback->getFallbackCatalogue();
|
|
||||||
}
|
|
||||||
|
|
||||||
ksort($messages);
|
|
||||||
|
|
||||||
return $messages;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Controller;
|
|
||||||
|
|
||||||
use App\Entity\Settings;
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
|
||||||
|
|
||||||
final class VersionController
|
|
||||||
{
|
|
||||||
#[Route('/api/version', name: 'api_version', methods: ['GET'])]
|
|
||||||
public function __invoke(EntityManagerInterface $entityManager): JsonResponse
|
|
||||||
{
|
|
||||||
$repository = $entityManager->getRepository(Settings::class);
|
|
||||||
$version = $repository->findOneBy(['key' => 'version']);
|
|
||||||
$build = $repository->findOneBy(['key' => 'build']);
|
|
||||||
|
|
||||||
return new JsonResponse([
|
|
||||||
'version' => $version?->getValue(),
|
|
||||||
'build' => $build ? (int) $build->getValue() : null,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0
api/src/Entity/.gitignore
vendored
0
api/src/Entity/.gitignore
vendored
@@ -1,205 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Entity;
|
|
||||||
|
|
||||||
use ApiPlatform\Doctrine\Orm\Filter\ExistsFilter;
|
|
||||||
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
|
|
||||||
use ApiPlatform\Metadata\ApiFilter;
|
|
||||||
use ApiPlatform\Metadata\ApiResource;
|
|
||||||
use ApiPlatform\Metadata\Delete;
|
|
||||||
use ApiPlatform\Metadata\Get;
|
|
||||||
use ApiPlatform\Metadata\GetCollection;
|
|
||||||
use ApiPlatform\Metadata\Patch;
|
|
||||||
use ApiPlatform\Metadata\Post;
|
|
||||||
use App\State\ForumPositionProcessor;
|
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
|
||||||
use Doctrine\Common\Collections\Collection;
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
|
||||||
//use Symfony\Component\Serializer\Annotation\Groups;
|
|
||||||
use Symfony\Component\Serializer\Attribute\Groups;
|
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
|
||||||
|
|
||||||
#[ORM\Entity]
|
|
||||||
#[ORM\HasLifecycleCallbacks]
|
|
||||||
#[ORM\Table(indexes: [
|
|
||||||
new ORM\Index(name: 'idx_forum_parent_position', columns: ['parent_id', 'position']),
|
|
||||||
new ORM\Index(name: 'idx_forum_type', columns: ['type']),
|
|
||||||
])]
|
|
||||||
#[ApiFilter(SearchFilter::class, properties: ['parent' => 'exact', 'type' => 'exact'])]
|
|
||||||
#[ApiFilter(ExistsFilter::class, properties: ['parent'])]
|
|
||||||
#[ApiResource(
|
|
||||||
operations : [
|
|
||||||
new Get(),
|
|
||||||
new GetCollection(),
|
|
||||||
new Post(security: "is_granted('ROLE_ADMIN')", processor: ForumPositionProcessor::class),
|
|
||||||
new Patch(security: "is_granted('ROLE_ADMIN')", processor: ForumPositionProcessor::class),
|
|
||||||
new Delete(security: "is_granted('ROLE_ADMIN')")
|
|
||||||
],
|
|
||||||
normalizationContext : ['groups' => ['forum:read']],
|
|
||||||
denormalizationContext: ['groups' => ['forum:write']],
|
|
||||||
order : ['position' => 'ASC']
|
|
||||||
)]
|
|
||||||
class Forum
|
|
||||||
{
|
|
||||||
public const TYPE_CATEGORY = 'category';
|
|
||||||
public const TYPE_FORUM = 'forum';
|
|
||||||
|
|
||||||
#[ORM\Id]
|
|
||||||
#[ORM\GeneratedValue]
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['forum:read', 'thread:read'])]
|
|
||||||
private ?int $id = null;
|
|
||||||
|
|
||||||
#[ORM\Column(length: 100)]
|
|
||||||
#[Assert\NotBlank]
|
|
||||||
#[Groups(['forum:read', 'forum:write', 'thread:read'])]
|
|
||||||
private ?string $name = null;
|
|
||||||
|
|
||||||
#[ORM\Column(type: 'text', nullable: true)]
|
|
||||||
#[Groups(['forum:read', 'forum:write'])]
|
|
||||||
private ?string $description = null;
|
|
||||||
|
|
||||||
#[ORM\Column(length: 20)]
|
|
||||||
#[Assert\Choice(choices: [self::TYPE_CATEGORY, self::TYPE_FORUM])]
|
|
||||||
#[Groups(['forum:read', 'forum:write'])]
|
|
||||||
private string $type = self::TYPE_CATEGORY;
|
|
||||||
|
|
||||||
#[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')]
|
|
||||||
#[Assert\Expression(
|
|
||||||
"this.getParent() === null or this.getParent().isCategory()",
|
|
||||||
message: "Parent must be a category."
|
|
||||||
)]
|
|
||||||
#[Groups(['forum:read', 'forum:write'])]
|
|
||||||
private ?self $parent = null;
|
|
||||||
|
|
||||||
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)]
|
|
||||||
#[Groups(['forum:read'])]
|
|
||||||
private Collection $children;
|
|
||||||
|
|
||||||
#[ORM\OneToMany(mappedBy: 'forum', targetEntity: Thread::class)]
|
|
||||||
#[Groups(['forum:read'])]
|
|
||||||
private Collection $threads;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['forum:read'])]
|
|
||||||
private int $position = 0;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['forum:read'])]
|
|
||||||
private ?\DateTimeImmutable $createdAt = null;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['forum:read'])]
|
|
||||||
private ?\DateTimeImmutable $updatedAt = null;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->children = new ArrayCollection();
|
|
||||||
$this->threads = new ArrayCollection();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ORM\PrePersist]
|
|
||||||
public function onCreate(): void
|
|
||||||
{
|
|
||||||
$now = new \DateTimeImmutable();
|
|
||||||
$this->createdAt = $now;
|
|
||||||
$this->updatedAt = $now;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ORM\PreUpdate]
|
|
||||||
public function onUpdate(): void
|
|
||||||
{
|
|
||||||
$this->updatedAt = new \DateTimeImmutable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId(): ?int
|
|
||||||
{
|
|
||||||
return $this->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getName(): ?string
|
|
||||||
{
|
|
||||||
return $this->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setName(string $name): self
|
|
||||||
{
|
|
||||||
$this->name = $name;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription(): ?string
|
|
||||||
{
|
|
||||||
return $this->description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setDescription(?string $description): self
|
|
||||||
{
|
|
||||||
$this->description = $description;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getType(): string
|
|
||||||
{
|
|
||||||
return $this->type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setType(string $type): self
|
|
||||||
{
|
|
||||||
$this->type = $type;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getParent(): ?self
|
|
||||||
{
|
|
||||||
return $this->parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setParent(?self $parent): self
|
|
||||||
{
|
|
||||||
$this->parent = $parent;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Collection<int, Forum>
|
|
||||||
*/
|
|
||||||
public function getChildren(): Collection
|
|
||||||
{
|
|
||||||
return $this->children;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPosition(): int
|
|
||||||
{
|
|
||||||
return $this->position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setPosition(int $position): self
|
|
||||||
{
|
|
||||||
$this->position = $position;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Collection<int, Thread>
|
|
||||||
*/
|
|
||||||
public function getThreads(): Collection
|
|
||||||
{
|
|
||||||
return $this->threads;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isCategory(): bool
|
|
||||||
{
|
|
||||||
return $this->type === self::TYPE_CATEGORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isForum(): bool
|
|
||||||
{
|
|
||||||
return $this->type === self::TYPE_FORUM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Entity;
|
|
||||||
|
|
||||||
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
|
|
||||||
use ApiPlatform\Metadata\ApiFilter;
|
|
||||||
use ApiPlatform\Metadata\ApiResource;
|
|
||||||
use ApiPlatform\Metadata\Delete;
|
|
||||||
use ApiPlatform\Metadata\Get;
|
|
||||||
use ApiPlatform\Metadata\GetCollection;
|
|
||||||
use ApiPlatform\Metadata\Patch;
|
|
||||||
use ApiPlatform\Metadata\Post as PostOperation;
|
|
||||||
use App\State\PostOwnerProcessor;
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
|
||||||
use Symfony\Component\Serializer\Annotation\Groups;
|
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
|
||||||
|
|
||||||
#[ORM\Entity]
|
|
||||||
#[ORM\HasLifecycleCallbacks]
|
|
||||||
#[ApiFilter(SearchFilter::class, properties: ['thread' => 'exact'])]
|
|
||||||
#[ApiResource(
|
|
||||||
normalizationContext: ['groups' => ['post:read']],
|
|
||||||
denormalizationContext: ['groups' => ['post:write']],
|
|
||||||
operations: [
|
|
||||||
new Get(),
|
|
||||||
new GetCollection(),
|
|
||||||
new PostOperation(
|
|
||||||
security: "is_granted('ROLE_USER')",
|
|
||||||
processor: PostOwnerProcessor::class
|
|
||||||
),
|
|
||||||
new Patch(security: "is_granted('ROLE_ADMIN') or object.getAuthor() == user"),
|
|
||||||
new Delete(security: "is_granted('ROLE_ADMIN') or object.getAuthor() == user")
|
|
||||||
]
|
|
||||||
)]
|
|
||||||
class Post
|
|
||||||
{
|
|
||||||
#[ORM\Id]
|
|
||||||
#[ORM\GeneratedValue]
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['post:read', 'thread:read'])]
|
|
||||||
private ?int $id = null;
|
|
||||||
|
|
||||||
#[ORM\Column(type: 'text')]
|
|
||||||
#[Assert\NotBlank]
|
|
||||||
#[Groups(['post:read', 'post:write', 'thread:read'])]
|
|
||||||
private ?string $body = null;
|
|
||||||
|
|
||||||
#[ORM\ManyToOne(targetEntity: Thread::class, inversedBy: 'posts')]
|
|
||||||
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
|
|
||||||
#[Assert\NotNull]
|
|
||||||
#[Groups(['post:read', 'post:write'])]
|
|
||||||
private ?Thread $thread = null;
|
|
||||||
|
|
||||||
#[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'posts')]
|
|
||||||
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
|
|
||||||
#[Groups(['post:read'])]
|
|
||||||
private ?User $author = null;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['post:read'])]
|
|
||||||
private ?\DateTimeImmutable $createdAt = null;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['post:read'])]
|
|
||||||
private ?\DateTimeImmutable $updatedAt = null;
|
|
||||||
|
|
||||||
#[ORM\PrePersist]
|
|
||||||
public function onCreate(): void
|
|
||||||
{
|
|
||||||
$now = new \DateTimeImmutable();
|
|
||||||
$this->createdAt = $now;
|
|
||||||
$this->updatedAt = $now;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ORM\PreUpdate]
|
|
||||||
public function onUpdate(): void
|
|
||||||
{
|
|
||||||
$this->updatedAt = new \DateTimeImmutable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId(): ?int
|
|
||||||
{
|
|
||||||
return $this->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBody(): ?string
|
|
||||||
{
|
|
||||||
return $this->body;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setBody(string $body): self
|
|
||||||
{
|
|
||||||
$this->body = $body;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getThread(): ?Thread
|
|
||||||
{
|
|
||||||
return $this->thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setThread(?Thread $thread): self
|
|
||||||
{
|
|
||||||
$this->thread = $thread;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAuthor(): ?User
|
|
||||||
{
|
|
||||||
return $this->author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setAuthor(?User $author): self
|
|
||||||
{
|
|
||||||
$this->author = $author;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCreatedAt(): ?\DateTimeImmutable
|
|
||||||
{
|
|
||||||
return $this->createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUpdatedAt(): ?\DateTimeImmutable
|
|
||||||
{
|
|
||||||
return $this->updatedAt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Entity;
|
|
||||||
|
|
||||||
use ApiPlatform\Metadata\ApiResource;
|
|
||||||
use ApiPlatform\Metadata\Get;
|
|
||||||
use ApiPlatform\Metadata\GetCollection;
|
|
||||||
use ApiPlatform\Metadata\Patch;
|
|
||||||
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
|
|
||||||
use ApiPlatform\Metadata\ApiFilter;
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
|
||||||
use Symfony\Component\Serializer\Attribute\Groups;
|
|
||||||
|
|
||||||
#[ORM\Entity]
|
|
||||||
#[ApiFilter(SearchFilter::class, properties: ['key' => 'exact'])]
|
|
||||||
#[ApiResource(
|
|
||||||
operations : [
|
|
||||||
new Get(),
|
|
||||||
new GetCollection(),
|
|
||||||
new Patch(security: "is_granted('ROLE_ADMIN')")
|
|
||||||
],
|
|
||||||
normalizationContext : ['groups' => ['settings:read']],
|
|
||||||
denormalizationContext: ['groups' => ['settings:write']]
|
|
||||||
)]
|
|
||||||
class Settings
|
|
||||||
{
|
|
||||||
#[ORM\Id]
|
|
||||||
#[ORM\GeneratedValue]
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['settings:read'])]
|
|
||||||
private ?int $id = null;
|
|
||||||
|
|
||||||
#[ORM\Column(length: 100, unique: true)]
|
|
||||||
#[Groups(['settings:read', 'settings:write'])]
|
|
||||||
private string $key = '';
|
|
||||||
|
|
||||||
#[ORM\Column(type: 'text')]
|
|
||||||
#[Groups(['settings:read', 'settings:write'])]
|
|
||||||
private string $value = '';
|
|
||||||
|
|
||||||
public function getId(): ?int
|
|
||||||
{
|
|
||||||
return $this->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getKey(): string
|
|
||||||
{
|
|
||||||
return $this->key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setKey(string $key): self
|
|
||||||
{
|
|
||||||
$this->key = $key;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getValue(): string
|
|
||||||
{
|
|
||||||
return $this->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setValue(string $value): self
|
|
||||||
{
|
|
||||||
$this->value = $value;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Entity;
|
|
||||||
|
|
||||||
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
|
|
||||||
use ApiPlatform\Metadata\ApiFilter;
|
|
||||||
use ApiPlatform\Metadata\ApiResource;
|
|
||||||
use ApiPlatform\Metadata\Delete;
|
|
||||||
use ApiPlatform\Metadata\Get;
|
|
||||||
use ApiPlatform\Metadata\GetCollection;
|
|
||||||
use ApiPlatform\Metadata\Patch;
|
|
||||||
use ApiPlatform\Metadata\Post as PostOperation;
|
|
||||||
use App\State\ThreadOwnerProcessor;
|
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
|
||||||
use Doctrine\Common\Collections\Collection;
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
|
||||||
use Symfony\Component\Serializer\Annotation\Groups;
|
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
|
||||||
|
|
||||||
#[ORM\Entity]
|
|
||||||
#[ORM\HasLifecycleCallbacks]
|
|
||||||
#[ApiFilter(SearchFilter::class, properties: ['forum' => 'exact'])]
|
|
||||||
#[ApiResource(
|
|
||||||
normalizationContext: ['groups' => ['thread:read']],
|
|
||||||
denormalizationContext: ['groups' => ['thread:write']],
|
|
||||||
operations: [
|
|
||||||
new Get(),
|
|
||||||
new GetCollection(),
|
|
||||||
new PostOperation(
|
|
||||||
security: "is_granted('ROLE_USER')",
|
|
||||||
processor: ThreadOwnerProcessor::class
|
|
||||||
),
|
|
||||||
new Patch(security: "is_granted('ROLE_ADMIN') or object.getAuthor() == user"),
|
|
||||||
new Delete(security: "is_granted('ROLE_ADMIN') or object.getAuthor() == user")
|
|
||||||
]
|
|
||||||
)]
|
|
||||||
class Thread
|
|
||||||
{
|
|
||||||
#[ORM\Id]
|
|
||||||
#[ORM\GeneratedValue]
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['thread:read', 'forum:read', 'post:read'])]
|
|
||||||
private ?int $id = null;
|
|
||||||
|
|
||||||
#[ORM\Column(length: 200)]
|
|
||||||
#[Assert\NotBlank]
|
|
||||||
#[Groups(['thread:read', 'thread:write', 'forum:read', 'post:read'])]
|
|
||||||
private ?string $title = null;
|
|
||||||
|
|
||||||
#[ORM\Column(type: 'text')]
|
|
||||||
#[Assert\NotBlank]
|
|
||||||
#[Groups(['thread:read', 'thread:write'])]
|
|
||||||
private ?string $body = null;
|
|
||||||
|
|
||||||
#[ORM\ManyToOne(targetEntity: Forum::class, inversedBy: 'threads')]
|
|
||||||
#[ORM\JoinColumn(nullable: false)]
|
|
||||||
#[Assert\NotNull]
|
|
||||||
#[Assert\Expression("this.getForum() and this.getForum().isForum()", message: "Thread must belong to a forum.")]
|
|
||||||
#[Groups(['thread:read', 'thread:write'])]
|
|
||||||
private ?Forum $forum = null;
|
|
||||||
|
|
||||||
#[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'threads')]
|
|
||||||
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
|
|
||||||
#[Groups(['thread:read'])]
|
|
||||||
private ?User $author = null;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['thread:read'])]
|
|
||||||
private ?\DateTimeImmutable $createdAt = null;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['thread:read'])]
|
|
||||||
private ?\DateTimeImmutable $updatedAt = null;
|
|
||||||
|
|
||||||
#[ORM\OneToMany(mappedBy: 'thread', targetEntity: Post::class)]
|
|
||||||
#[Groups(['thread:read'])]
|
|
||||||
private Collection $posts;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->posts = new ArrayCollection();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ORM\PrePersist]
|
|
||||||
public function onCreate(): void
|
|
||||||
{
|
|
||||||
$now = new \DateTimeImmutable();
|
|
||||||
$this->createdAt = $now;
|
|
||||||
$this->updatedAt = $now;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ORM\PreUpdate]
|
|
||||||
public function onUpdate(): void
|
|
||||||
{
|
|
||||||
$this->updatedAt = new \DateTimeImmutable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId(): ?int
|
|
||||||
{
|
|
||||||
return $this->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTitle(): ?string
|
|
||||||
{
|
|
||||||
return $this->title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setTitle(string $title): self
|
|
||||||
{
|
|
||||||
$this->title = $title;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBody(): ?string
|
|
||||||
{
|
|
||||||
return $this->body;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setBody(string $body): self
|
|
||||||
{
|
|
||||||
$this->body = $body;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getForum(): ?Forum
|
|
||||||
{
|
|
||||||
return $this->forum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setForum(?Forum $forum): self
|
|
||||||
{
|
|
||||||
$this->forum = $forum;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAuthor(): ?User
|
|
||||||
{
|
|
||||||
return $this->author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setAuthor(?User $author): self
|
|
||||||
{
|
|
||||||
$this->author = $author;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCreatedAt(): ?\DateTimeImmutable
|
|
||||||
{
|
|
||||||
return $this->createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUpdatedAt(): ?\DateTimeImmutable
|
|
||||||
{
|
|
||||||
return $this->updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Collection<int, Post>
|
|
||||||
*/
|
|
||||||
public function getPosts(): Collection
|
|
||||||
{
|
|
||||||
return $this->posts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,212 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Entity;
|
|
||||||
|
|
||||||
use ApiPlatform\Metadata\ApiResource;
|
|
||||||
use ApiPlatform\Metadata\Delete;
|
|
||||||
use ApiPlatform\Metadata\Get;
|
|
||||||
use ApiPlatform\Metadata\GetCollection;
|
|
||||||
use ApiPlatform\Metadata\Patch;
|
|
||||||
use ApiPlatform\Metadata\Post as PostOperation;
|
|
||||||
use App\State\UserPasswordHasherProcessor;
|
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
|
||||||
use Doctrine\Common\Collections\Collection;
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|
||||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
|
||||||
use Symfony\Component\Serializer\Annotation\Groups;
|
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
|
||||||
|
|
||||||
#[ORM\Entity]
|
|
||||||
#[ORM\Table(name: 'users')]
|
|
||||||
#[UniqueEntity(fields: ['email'])]
|
|
||||||
#[UniqueEntity(fields: ['username'])]
|
|
||||||
#[ORM\HasLifecycleCallbacks]
|
|
||||||
#[ApiResource(
|
|
||||||
normalizationContext: ['groups' => ['user:read']],
|
|
||||||
denormalizationContext: ['groups' => ['user:write']],
|
|
||||||
operations: [
|
|
||||||
new Get(security: "is_granted('ROLE_ADMIN')"),
|
|
||||||
new GetCollection(security: "is_granted('ROLE_ADMIN')"),
|
|
||||||
new PostOperation(
|
|
||||||
security: "is_granted('PUBLIC_ACCESS')",
|
|
||||||
processor: UserPasswordHasherProcessor::class,
|
|
||||||
validationContext: ['groups' => ['Default', 'user:create']]
|
|
||||||
),
|
|
||||||
new Patch(
|
|
||||||
security: "is_granted('ROLE_ADMIN') or object == user",
|
|
||||||
processor: UserPasswordHasherProcessor::class
|
|
||||||
),
|
|
||||||
new Delete(security: "is_granted('ROLE_ADMIN')")
|
|
||||||
]
|
|
||||||
)]
|
|
||||||
class User implements UserInterface, PasswordAuthenticatedUserInterface
|
|
||||||
{
|
|
||||||
#[ORM\Id]
|
|
||||||
#[ORM\GeneratedValue]
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['user:read', 'thread:read', 'post:read'])]
|
|
||||||
private ?int $id = null;
|
|
||||||
|
|
||||||
#[ORM\Column(length: 180, unique: true)]
|
|
||||||
#[Assert\NotBlank]
|
|
||||||
#[Assert\Email]
|
|
||||||
#[Groups(['user:read', 'user:write', 'thread:read', 'post:read'])]
|
|
||||||
private ?string $email = null;
|
|
||||||
|
|
||||||
#[ORM\Column(length: 50, unique: true)]
|
|
||||||
#[Assert\NotBlank]
|
|
||||||
#[Assert\Length(min: 3, max: 50)]
|
|
||||||
#[Groups(['user:read', 'user:write', 'thread:read', 'post:read'])]
|
|
||||||
private ?string $username = null;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
private array $roles = [];
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
private ?string $password = null;
|
|
||||||
|
|
||||||
#[Assert\NotBlank(groups: ['user:create'])]
|
|
||||||
#[Assert\Length(min: 8)]
|
|
||||||
#[Groups(['user:write'])]
|
|
||||||
private ?string $plainPassword = null;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['user:read'])]
|
|
||||||
private ?\DateTimeImmutable $createdAt = null;
|
|
||||||
|
|
||||||
#[ORM\Column]
|
|
||||||
#[Groups(['user:read'])]
|
|
||||||
private ?\DateTimeImmutable $updatedAt = null;
|
|
||||||
|
|
||||||
#[ORM\OneToMany(mappedBy: 'author', targetEntity: Thread::class)]
|
|
||||||
private Collection $threads;
|
|
||||||
|
|
||||||
#[ORM\OneToMany(mappedBy: 'author', targetEntity: Post::class)]
|
|
||||||
private Collection $posts;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->threads = new ArrayCollection();
|
|
||||||
$this->posts = new ArrayCollection();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ORM\PrePersist]
|
|
||||||
public function onCreate(): void
|
|
||||||
{
|
|
||||||
$now = new \DateTimeImmutable();
|
|
||||||
$this->createdAt = $now;
|
|
||||||
$this->updatedAt = $now;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ORM\PreUpdate]
|
|
||||||
public function onUpdate(): void
|
|
||||||
{
|
|
||||||
$this->updatedAt = new \DateTimeImmutable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId(): ?int
|
|
||||||
{
|
|
||||||
return $this->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEmail(): ?string
|
|
||||||
{
|
|
||||||
return $this->email;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setEmail(string $email): self
|
|
||||||
{
|
|
||||||
$this->email = $email;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUsername(): ?string
|
|
||||||
{
|
|
||||||
return $this->username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setUsername(string $username): self
|
|
||||||
{
|
|
||||||
$this->username = $username;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUserIdentifier(): string
|
|
||||||
{
|
|
||||||
return (string) $this->email;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRoles(): array
|
|
||||||
{
|
|
||||||
$roles = $this->roles;
|
|
||||||
$roles[] = 'ROLE_USER';
|
|
||||||
|
|
||||||
return array_unique($roles);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setRoles(array $roles): self
|
|
||||||
{
|
|
||||||
$this->roles = $roles;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPassword(): ?string
|
|
||||||
{
|
|
||||||
return $this->password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setPassword(string $password): self
|
|
||||||
{
|
|
||||||
$this->password = $password;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPlainPassword(): ?string
|
|
||||||
{
|
|
||||||
return $this->plainPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setPlainPassword(?string $plainPassword): self
|
|
||||||
{
|
|
||||||
$this->plainPassword = $plainPassword;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function eraseCredentials(): void
|
|
||||||
{
|
|
||||||
$this->plainPassword = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCreatedAt(): ?\DateTimeImmutable
|
|
||||||
{
|
|
||||||
return $this->createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUpdatedAt(): ?\DateTimeImmutable
|
|
||||||
{
|
|
||||||
return $this->updatedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Collection<int, Thread>
|
|
||||||
*/
|
|
||||||
public function getThreads(): Collection
|
|
||||||
{
|
|
||||||
return $this->threads;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Collection<int, Post>
|
|
||||||
*/
|
|
||||||
public function getPosts(): Collection
|
|
||||||
{
|
|
||||||
return $this->posts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\EventSubscriber;
|
|
||||||
|
|
||||||
use App\Entity\User;
|
|
||||||
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent;
|
|
||||||
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
|
|
||||||
|
|
||||||
#[AsEventListener(event: 'lexik_jwt_authentication.on_jwt_created')]
|
|
||||||
class JwtCreatedSubscriber
|
|
||||||
{
|
|
||||||
public function __invoke(JWTCreatedEvent $event): void
|
|
||||||
{
|
|
||||||
$user = $event->getUser();
|
|
||||||
if (!$user instanceof User) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$payload = $event->getData();
|
|
||||||
$payload['user_id'] = $user->getId();
|
|
||||||
$payload['username'] = $user->getEmail();
|
|
||||||
$payload['display_name'] = $user->getUsername();
|
|
||||||
$event->setData($payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App;
|
|
||||||
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
|
||||||
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
|
|
||||||
|
|
||||||
class Kernel extends BaseKernel
|
|
||||||
{
|
|
||||||
use MicroKernelTrait;
|
|
||||||
}
|
|
||||||
0
api/src/Repository/.gitignore
vendored
0
api/src/Repository/.gitignore
vendored
@@ -1,47 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\State;
|
|
||||||
|
|
||||||
use ApiPlatform\Metadata\Operation;
|
|
||||||
use ApiPlatform\State\ProcessorInterface;
|
|
||||||
use App\Entity\Forum;
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
|
||||||
|
|
||||||
class ForumPositionProcessor implements ProcessorInterface
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private EntityManagerInterface $entityManager,
|
|
||||||
#[Autowire(service: 'api_platform.doctrine.orm.state.persist_processor')]
|
|
||||||
private ProcessorInterface $persistProcessor
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
|
|
||||||
{
|
|
||||||
if (!$data instanceof Forum) {
|
|
||||||
return $this->persistProcessor->process($data, $operation, $uriVariables, $context);
|
|
||||||
}
|
|
||||||
|
|
||||||
$previous = $context['previous_data'] ?? null;
|
|
||||||
$parentChanged = $previous instanceof Forum && $previous->getParent()?->getId() !== $data->getParent()?->getId();
|
|
||||||
|
|
||||||
if ($data->getPosition() === 0 || $parentChanged) {
|
|
||||||
$qb = $this->entityManager->createQueryBuilder();
|
|
||||||
$qb->select('COALESCE(MAX(f.position), 0)')
|
|
||||||
->from(Forum::class, 'f');
|
|
||||||
|
|
||||||
if ($data->getParent()) {
|
|
||||||
$qb->andWhere('f.parent = :parent')
|
|
||||||
->setParameter('parent', $data->getParent());
|
|
||||||
} else {
|
|
||||||
$qb->andWhere('f.parent IS NULL');
|
|
||||||
}
|
|
||||||
|
|
||||||
$maxPosition = (int) $qb->getQuery()->getSingleScalarResult();
|
|
||||||
$data->setPosition($maxPosition + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->persistProcessor->process($data, $operation, $uriVariables, $context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\State;
|
|
||||||
|
|
||||||
use ApiPlatform\Metadata\Operation;
|
|
||||||
use ApiPlatform\State\ProcessorInterface;
|
|
||||||
use App\Entity\Post;
|
|
||||||
use App\Entity\User;
|
|
||||||
use Symfony\Bundle\SecurityBundle\Security;
|
|
||||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
|
||||||
|
|
||||||
class PostOwnerProcessor implements ProcessorInterface
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private Security $security,
|
|
||||||
#[Autowire(service: 'api_platform.doctrine.orm.state.persist_processor')]
|
|
||||||
private ProcessorInterface $persistProcessor
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
|
|
||||||
{
|
|
||||||
if ($data instanceof Post && null === $data->getAuthor()) {
|
|
||||||
$user = $this->security->getUser();
|
|
||||||
if ($user instanceof User) {
|
|
||||||
$data->setAuthor($user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->persistProcessor->process($data, $operation, $uriVariables, $context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\State;
|
|
||||||
|
|
||||||
use ApiPlatform\Metadata\Operation;
|
|
||||||
use ApiPlatform\State\ProcessorInterface;
|
|
||||||
use App\Entity\Thread;
|
|
||||||
use App\Entity\User;
|
|
||||||
use Symfony\Bundle\SecurityBundle\Security;
|
|
||||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
|
||||||
|
|
||||||
class ThreadOwnerProcessor implements ProcessorInterface
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private Security $security,
|
|
||||||
#[Autowire(service: 'api_platform.doctrine.orm.state.persist_processor')]
|
|
||||||
private ProcessorInterface $persistProcessor
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
|
|
||||||
{
|
|
||||||
if ($data instanceof Thread && null === $data->getAuthor()) {
|
|
||||||
$user = $this->security->getUser();
|
|
||||||
if ($user instanceof User) {
|
|
||||||
$data->setAuthor($user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->persistProcessor->process($data, $operation, $uriVariables, $context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\State;
|
|
||||||
|
|
||||||
use ApiPlatform\Metadata\Operation;
|
|
||||||
use ApiPlatform\State\ProcessorInterface;
|
|
||||||
use App\Entity\User;
|
|
||||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
|
||||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
|
||||||
|
|
||||||
class UserPasswordHasherProcessor implements ProcessorInterface
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private UserPasswordHasherInterface $passwordHasher,
|
|
||||||
#[Autowire(service: 'api_platform.doctrine.orm.state.persist_processor')]
|
|
||||||
private ProcessorInterface $persistProcessor
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
|
|
||||||
{
|
|
||||||
if ($data instanceof User && $data->getPlainPassword()) {
|
|
||||||
$data->setPassword(
|
|
||||||
$this->passwordHasher->hashPassword($data, $data->getPlainPassword())
|
|
||||||
);
|
|
||||||
$data->eraseCredentials();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->persistProcessor->process($data, $operation, $uriVariables, $context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
203
api/symfony.lock
203
api/symfony.lock
@@ -1,203 +0,0 @@
|
|||||||
{
|
|
||||||
"api-platform/symfony": {
|
|
||||||
"version": "4.2",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "4.0",
|
|
||||||
"ref": "e9952e9f393c2d048f10a78f272cd35e807d972b"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"config/packages/api_platform.yaml",
|
|
||||||
"config/routes/api_platform.yaml",
|
|
||||||
"src/ApiResource/.gitignore"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"doctrine/deprecations": {
|
|
||||||
"version": "1.1",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "1.0",
|
|
||||||
"ref": "87424683adc81d7dc305eefec1fced883084aab9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"doctrine/doctrine-bundle": {
|
|
||||||
"version": "3.2",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "3.0",
|
|
||||||
"ref": "18ee08e513ba0303fd09a01fc1c934870af06ffa"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"config/packages/doctrine.yaml",
|
|
||||||
"src/Entity/.gitignore",
|
|
||||||
"src/Repository/.gitignore"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"doctrine/doctrine-migrations-bundle": {
|
|
||||||
"version": "4.0",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "3.1",
|
|
||||||
"ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"config/packages/doctrine_migrations.yaml",
|
|
||||||
"migrations/.gitignore"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lexik/jwt-authentication-bundle": {
|
|
||||||
"version": "3.2",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "2.5",
|
|
||||||
"ref": "e9481b233a11ef7e15fe055a2b21fd3ac1aa2bb7"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"config/packages/lexik_jwt_authentication.yaml"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"symfony/apache-pack": {
|
|
||||||
"version": "1.0",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes-contrib",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "1.0",
|
|
||||||
"ref": "5d454ec6cc4c700ed3d963f3803e1d427d9669fb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"symfony/console": {
|
|
||||||
"version": "8.0",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "5.3",
|
|
||||||
"ref": "1781ff40d8a17d87cf53f8d4cf0c8346ed2bb461"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"bin/console"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"symfony/flex": {
|
|
||||||
"version": "2.10",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "2.4",
|
|
||||||
"ref": "52e9754527a15e2b79d9a610f98185a1fe46622a"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
".env",
|
|
||||||
".env.dev"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"symfony/framework-bundle": {
|
|
||||||
"version": "8.0",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "7.4",
|
|
||||||
"ref": "09f6e081c763a206802674ce0cb34a022f0ffc6d"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"config/packages/cache.yaml",
|
|
||||||
"config/packages/framework.yaml",
|
|
||||||
"config/preload.php",
|
|
||||||
"config/routes/framework.yaml",
|
|
||||||
"config/services.yaml",
|
|
||||||
"public/index.php",
|
|
||||||
"src/Controller/.gitignore",
|
|
||||||
"src/Kernel.php",
|
|
||||||
".editorconfig"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"symfony/property-info": {
|
|
||||||
"version": "8.0",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "7.3",
|
|
||||||
"ref": "dae70df71978ae9226ae915ffd5fad817f5ca1f7"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"config/packages/property_info.yaml"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"symfony/routing": {
|
|
||||||
"version": "8.0",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "7.4",
|
|
||||||
"ref": "bc94c4fd86f393f3ab3947c18b830ea343e51ded"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"config/packages/routing.yaml",
|
|
||||||
"config/routes.yaml"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"symfony/security-bundle": {
|
|
||||||
"version": "8.0",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "7.4",
|
|
||||||
"ref": "c42fee7802181cdd50f61b8622715829f5d2335c"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"config/packages/security.yaml",
|
|
||||||
"config/routes/security.yaml"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"symfony/translation": {
|
|
||||||
"version": "8.0",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "6.3",
|
|
||||||
"ref": "620a1b84865ceb2ba304c8f8bf2a185fbf32a843"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"config/packages/translation.yaml",
|
|
||||||
"translations/.gitignore"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"symfony/twig-bundle": {
|
|
||||||
"version": "8.0",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "6.4",
|
|
||||||
"ref": "cab5fd2a13a45c266d45a7d9337e28dee6272877"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"config/packages/twig.yaml",
|
|
||||||
"templates/base.html.twig"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"symfony/uid": {
|
|
||||||
"version": "8.0",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "7.0",
|
|
||||||
"ref": "0df5844274d871b37fc3816c57a768ffc60a43a5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"symfony/validator": {
|
|
||||||
"version": "8.0",
|
|
||||||
"recipe": {
|
|
||||||
"repo": "github.com/symfony/recipes",
|
|
||||||
"branch": "main",
|
|
||||||
"version": "7.0",
|
|
||||||
"ref": "8c1c4e28d26a124b0bb273f537ca8ce443472bfd"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"config/packages/validator.yaml"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
|
||||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
|
||||||
{% block stylesheets %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block javascripts %}
|
|
||||||
{% endblock %}
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{% block body %}{% endblock %}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
0
api/translations/.gitignore
vendored
0
api/translations/.gitignore
vendored
@@ -1,283 +0,0 @@
|
|||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Language: de\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
|
|
||||||
msgid "app.brand"
|
|
||||||
msgstr "speedBB"
|
|
||||||
|
|
||||||
msgid "nav.forums"
|
|
||||||
msgstr "Foren"
|
|
||||||
|
|
||||||
msgid "nav.login"
|
|
||||||
msgstr "Anmelden"
|
|
||||||
|
|
||||||
msgid "nav.register"
|
|
||||||
msgstr "Registrieren"
|
|
||||||
|
|
||||||
msgid "nav.logout"
|
|
||||||
msgstr "Abmelden"
|
|
||||||
|
|
||||||
msgid "nav.language"
|
|
||||||
msgstr "Sprache"
|
|
||||||
|
|
||||||
msgid "nav.theme"
|
|
||||||
msgstr "Design"
|
|
||||||
|
|
||||||
msgid "nav.theme_auto"
|
|
||||||
msgstr "Auto"
|
|
||||||
|
|
||||||
msgid "nav.theme_light"
|
|
||||||
msgstr "Hell"
|
|
||||||
|
|
||||||
msgid "nav.theme_dark"
|
|
||||||
msgstr "Dunkel"
|
|
||||||
|
|
||||||
msgid "home.hero_title"
|
|
||||||
msgstr "Foren"
|
|
||||||
|
|
||||||
msgid "home.hero_body"
|
|
||||||
msgstr "Entdecke Diskussionen, stelle Fragen und teile Ideen in Kategorien und Foren."
|
|
||||||
|
|
||||||
msgid "home.browse"
|
|
||||||
msgstr "Foren durchsuchen"
|
|
||||||
|
|
||||||
msgid "home.loading"
|
|
||||||
msgstr "Foren werden geladen..."
|
|
||||||
|
|
||||||
msgid "home.empty"
|
|
||||||
msgstr "Noch keine Foren vorhanden. Lege das erste Forum in der API an."
|
|
||||||
|
|
||||||
msgid "forum.threads"
|
|
||||||
msgstr "Threads"
|
|
||||||
|
|
||||||
msgid "forum.start_thread"
|
|
||||||
msgstr "Thread starten"
|
|
||||||
|
|
||||||
msgid "forum.loading"
|
|
||||||
msgstr "Forum wird geladen..."
|
|
||||||
|
|
||||||
msgid "forum.type_category"
|
|
||||||
msgstr "Kategorie"
|
|
||||||
|
|
||||||
msgid "forum.type_forum"
|
|
||||||
msgstr "Forum"
|
|
||||||
|
|
||||||
msgid "forum.no_description"
|
|
||||||
msgstr "Noch keine Beschreibung vorhanden."
|
|
||||||
|
|
||||||
msgid "forum.empty_threads"
|
|
||||||
msgstr "Noch keine Threads vorhanden. Starte unten einen."
|
|
||||||
|
|
||||||
msgid "forum.login_hint"
|
|
||||||
msgstr "Melde dich an, um einen neuen Thread zu erstellen."
|
|
||||||
|
|
||||||
msgid "forum.open"
|
|
||||||
msgstr "Forum öffnen"
|
|
||||||
|
|
||||||
msgid "forum.children"
|
|
||||||
msgstr "Unterforen"
|
|
||||||
|
|
||||||
msgid "forum.empty_children"
|
|
||||||
msgstr "Noch keine Unterforen vorhanden."
|
|
||||||
|
|
||||||
msgid "forum.only_forums"
|
|
||||||
msgstr "Threads können nur in Foren erstellt werden."
|
|
||||||
|
|
||||||
msgid "thread.replies"
|
|
||||||
msgstr "Antworten"
|
|
||||||
|
|
||||||
msgid "thread.reply"
|
|
||||||
msgstr "Antworten"
|
|
||||||
|
|
||||||
msgid "thread.loading"
|
|
||||||
msgstr "Thread wird geladen..."
|
|
||||||
|
|
||||||
msgid "thread.label"
|
|
||||||
msgstr "Thread"
|
|
||||||
|
|
||||||
msgid "thread.category"
|
|
||||||
msgstr "Forum:"
|
|
||||||
|
|
||||||
msgid "thread.back_to_category"
|
|
||||||
msgstr "Zurück zum Forum"
|
|
||||||
|
|
||||||
msgid "thread.empty"
|
|
||||||
msgstr "Sei die erste Person, die antwortet."
|
|
||||||
|
|
||||||
msgid "thread.anonymous"
|
|
||||||
msgstr "Anonym"
|
|
||||||
|
|
||||||
msgid "thread.login_hint"
|
|
||||||
msgstr "Melde dich an, um auf diesen Thread zu antworten."
|
|
||||||
|
|
||||||
msgid "thread.view"
|
|
||||||
msgstr "Thread ansehen"
|
|
||||||
|
|
||||||
msgid "auth.login_title"
|
|
||||||
msgstr "Anmelden"
|
|
||||||
|
|
||||||
msgid "auth.login_hint"
|
|
||||||
msgstr "Melde dich an, um neue Threads zu starten und zu antworten."
|
|
||||||
|
|
||||||
msgid "auth.register_title"
|
|
||||||
msgstr "Konto erstellen"
|
|
||||||
|
|
||||||
msgid "auth.register_hint"
|
|
||||||
msgstr "Registriere dich mit E-Mail und einem eindeutigen Benutzernamen."
|
|
||||||
|
|
||||||
msgid "footer.copy"
|
|
||||||
msgstr "speedBB"
|
|
||||||
|
|
||||||
msgid "form.title"
|
|
||||||
msgstr "Titel"
|
|
||||||
|
|
||||||
msgid "form.body"
|
|
||||||
msgstr "Inhalt"
|
|
||||||
|
|
||||||
msgid "form.message"
|
|
||||||
msgstr "Nachricht"
|
|
||||||
|
|
||||||
msgid "form.email"
|
|
||||||
msgstr "E-Mail"
|
|
||||||
|
|
||||||
msgid "form.username"
|
|
||||||
msgstr "Benutzername"
|
|
||||||
|
|
||||||
msgid "form.password"
|
|
||||||
msgstr "Passwort"
|
|
||||||
|
|
||||||
msgid "form.thread_title_placeholder"
|
|
||||||
msgstr "Thema"
|
|
||||||
|
|
||||||
msgid "form.thread_body_placeholder"
|
|
||||||
msgstr "Teile den Kontext und deine Frage."
|
|
||||||
|
|
||||||
msgid "form.reply_placeholder"
|
|
||||||
msgstr "Schreibe deine Antwort."
|
|
||||||
|
|
||||||
msgid "form.posting"
|
|
||||||
msgstr "Wird gesendet..."
|
|
||||||
|
|
||||||
msgid "form.create_thread"
|
|
||||||
msgstr "Thread erstellen"
|
|
||||||
|
|
||||||
msgid "form.post_reply"
|
|
||||||
msgstr "Antwort posten"
|
|
||||||
|
|
||||||
msgid "form.signing_in"
|
|
||||||
msgstr "Anmeldung läuft..."
|
|
||||||
|
|
||||||
msgid "form.sign_in"
|
|
||||||
msgstr "Anmelden"
|
|
||||||
|
|
||||||
msgid "form.registering"
|
|
||||||
msgstr "Registrierung läuft..."
|
|
||||||
|
|
||||||
msgid "form.create_account"
|
|
||||||
msgstr "Konto erstellen"
|
|
||||||
|
|
||||||
msgid "nav.acp"
|
|
||||||
msgstr "ACP"
|
|
||||||
|
|
||||||
msgid "acp.title"
|
|
||||||
msgstr "Administrationsbereich"
|
|
||||||
|
|
||||||
msgid "acp.no_access"
|
|
||||||
msgstr "Du hast keinen Zugriff auf diesen Bereich."
|
|
||||||
|
|
||||||
msgid "acp.general"
|
|
||||||
msgstr "Allgemein"
|
|
||||||
|
|
||||||
msgid "acp.general_hint"
|
|
||||||
msgstr "Globale Einstellungen und Board-Konfiguration erscheinen hier."
|
|
||||||
|
|
||||||
msgid "acp.forums"
|
|
||||||
msgstr "Foren"
|
|
||||||
|
|
||||||
msgid "acp.forums_hint"
|
|
||||||
msgstr "Kategorien und Foren in einer Baumansicht verwalten."
|
|
||||||
|
|
||||||
msgid "acp.users"
|
|
||||||
msgstr "Benutzer"
|
|
||||||
|
|
||||||
msgid "acp.users_hint"
|
|
||||||
msgstr "Werkzeuge zur Benutzerverwaltung erscheinen hier."
|
|
||||||
|
|
||||||
msgid "acp.forums_tree"
|
|
||||||
msgstr "Forenbaum"
|
|
||||||
|
|
||||||
msgid "acp.forums_empty"
|
|
||||||
msgstr "Noch keine Foren vorhanden. Lege rechts das erste an."
|
|
||||||
|
|
||||||
msgid "acp.forums_create_title"
|
|
||||||
msgstr "Forum oder Kategorie erstellen"
|
|
||||||
|
|
||||||
msgid "acp.forums_edit_title"
|
|
||||||
msgstr "Forum bearbeiten"
|
|
||||||
|
|
||||||
msgid "acp.forums_type"
|
|
||||||
msgstr "Typ"
|
|
||||||
|
|
||||||
msgid "acp.forums_parent"
|
|
||||||
msgstr "Übergeordnete Kategorie"
|
|
||||||
|
|
||||||
msgid "acp.forums_parent_root"
|
|
||||||
msgstr "Wurzel (kein Parent)"
|
|
||||||
|
|
||||||
msgid "acp.forums_confirm_delete"
|
|
||||||
msgstr "Dieses Forum löschen? Das kann nicht rückgängig gemacht werden."
|
|
||||||
|
|
||||||
msgid "acp.loading"
|
|
||||||
msgstr "Laden..."
|
|
||||||
|
|
||||||
msgid "acp.refresh"
|
|
||||||
msgstr "Aktualisieren"
|
|
||||||
|
|
||||||
msgid "acp.create"
|
|
||||||
msgstr "Erstellen"
|
|
||||||
|
|
||||||
msgid "acp.save"
|
|
||||||
msgstr "Speichern"
|
|
||||||
|
|
||||||
msgid "acp.reset"
|
|
||||||
msgstr "Zurücksetzen"
|
|
||||||
|
|
||||||
msgid "acp.edit"
|
|
||||||
msgstr "Bearbeiten"
|
|
||||||
|
|
||||||
msgid "acp.delete"
|
|
||||||
msgstr "Löschen"
|
|
||||||
|
|
||||||
msgid "form.description"
|
|
||||||
msgstr "Beschreibung"
|
|
||||||
|
|
||||||
msgid "acp.new_category"
|
|
||||||
msgstr "Neue Kategorie"
|
|
||||||
|
|
||||||
msgid "acp.new_forum"
|
|
||||||
msgstr "Neues Forum"
|
|
||||||
|
|
||||||
msgid "acp.forums_form_hint"
|
|
||||||
msgstr "Erstelle ein neues Forum oder bearbeite das ausgewählte. Kategorien können Foren und andere Kategorien enthalten."
|
|
||||||
|
|
||||||
msgid "acp.forums_name_required"
|
|
||||||
msgstr "Bitte zuerst einen Namen eingeben."
|
|
||||||
|
|
||||||
msgid "acp.drag_handle"
|
|
||||||
msgstr "Zum Sortieren ziehen"
|
|
||||||
|
|
||||||
msgid "acp.expand_all"
|
|
||||||
msgstr "Alle ausklappen"
|
|
||||||
|
|
||||||
msgid "acp.collapse_all"
|
|
||||||
msgstr "Alle einklappen"
|
|
||||||
|
|
||||||
msgid "acp.forums_form_empty_title"
|
|
||||||
msgstr "Keine Auswahl"
|
|
||||||
|
|
||||||
msgid "acp.forums_form_empty_hint"
|
|
||||||
msgstr "Wähle ein Forum zum Bearbeiten oder klicke auf Neue Kategorie / Neues Forum."
|
|
||||||
|
|
||||||
msgid "acp.cancel"
|
|
||||||
msgstr "Abbrechen"
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Language: en\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
|
|
||||||
msgid "app.brand"
|
|
||||||
msgstr "speedBB"
|
|
||||||
|
|
||||||
msgid "nav.forums"
|
|
||||||
msgstr "Forums"
|
|
||||||
|
|
||||||
msgid "nav.login"
|
|
||||||
msgstr "Login"
|
|
||||||
|
|
||||||
msgid "nav.register"
|
|
||||||
msgstr "Register"
|
|
||||||
|
|
||||||
msgid "nav.logout"
|
|
||||||
msgstr "Logout"
|
|
||||||
|
|
||||||
msgid "nav.language"
|
|
||||||
msgstr "Language"
|
|
||||||
|
|
||||||
msgid "nav.theme"
|
|
||||||
msgstr "Theme"
|
|
||||||
|
|
||||||
msgid "nav.theme_auto"
|
|
||||||
msgstr "Auto"
|
|
||||||
|
|
||||||
msgid "nav.theme_light"
|
|
||||||
msgstr "Light"
|
|
||||||
|
|
||||||
msgid "nav.theme_dark"
|
|
||||||
msgstr "Dark"
|
|
||||||
|
|
||||||
msgid "home.hero_title"
|
|
||||||
msgstr "Forums"
|
|
||||||
|
|
||||||
msgid "home.hero_body"
|
|
||||||
msgstr "Explore conversations, ask questions, and share ideas across categories and forums."
|
|
||||||
|
|
||||||
msgid "home.browse"
|
|
||||||
msgstr "Browse forums"
|
|
||||||
|
|
||||||
msgid "home.loading"
|
|
||||||
msgstr "Loading forums..."
|
|
||||||
|
|
||||||
msgid "home.empty"
|
|
||||||
msgstr "No forums yet. Create the first one in the API."
|
|
||||||
|
|
||||||
msgid "forum.threads"
|
|
||||||
msgstr "Threads"
|
|
||||||
|
|
||||||
msgid "forum.start_thread"
|
|
||||||
msgstr "Start a thread"
|
|
||||||
|
|
||||||
msgid "forum.loading"
|
|
||||||
msgstr "Loading forum..."
|
|
||||||
|
|
||||||
msgid "forum.type_category"
|
|
||||||
msgstr "Category"
|
|
||||||
|
|
||||||
msgid "forum.type_forum"
|
|
||||||
msgstr "Forum"
|
|
||||||
|
|
||||||
msgid "forum.no_description"
|
|
||||||
msgstr "No description added yet."
|
|
||||||
|
|
||||||
msgid "forum.empty_threads"
|
|
||||||
msgstr "No threads here yet. Start one below."
|
|
||||||
|
|
||||||
msgid "forum.login_hint"
|
|
||||||
msgstr "Log in to create a new thread."
|
|
||||||
|
|
||||||
msgid "forum.open"
|
|
||||||
msgstr "Open forum"
|
|
||||||
|
|
||||||
msgid "forum.children"
|
|
||||||
msgstr "Sub-forums"
|
|
||||||
|
|
||||||
msgid "forum.empty_children"
|
|
||||||
msgstr "No sub-forums yet."
|
|
||||||
|
|
||||||
msgid "forum.only_forums"
|
|
||||||
msgstr "Threads can only be created in forums."
|
|
||||||
|
|
||||||
msgid "thread.replies"
|
|
||||||
msgstr "Replies"
|
|
||||||
|
|
||||||
msgid "thread.reply"
|
|
||||||
msgstr "Reply"
|
|
||||||
|
|
||||||
msgid "thread.loading"
|
|
||||||
msgstr "Loading thread..."
|
|
||||||
|
|
||||||
msgid "thread.label"
|
|
||||||
msgstr "Thread"
|
|
||||||
|
|
||||||
msgid "thread.category"
|
|
||||||
msgstr "Forum:"
|
|
||||||
|
|
||||||
msgid "thread.back_to_category"
|
|
||||||
msgstr "Back to forum"
|
|
||||||
|
|
||||||
msgid "thread.empty"
|
|
||||||
msgstr "Be the first to reply."
|
|
||||||
|
|
||||||
msgid "thread.anonymous"
|
|
||||||
msgstr "Anonymous"
|
|
||||||
|
|
||||||
msgid "thread.login_hint"
|
|
||||||
msgstr "Log in to reply to this thread."
|
|
||||||
|
|
||||||
msgid "thread.view"
|
|
||||||
msgstr "View thread"
|
|
||||||
|
|
||||||
msgid "auth.login_title"
|
|
||||||
msgstr "Log in"
|
|
||||||
|
|
||||||
msgid "auth.login_hint"
|
|
||||||
msgstr "Access your account to start new threads and reply."
|
|
||||||
|
|
||||||
msgid "auth.register_title"
|
|
||||||
msgstr "Create account"
|
|
||||||
|
|
||||||
msgid "auth.register_hint"
|
|
||||||
msgstr "Register with an email and a unique username."
|
|
||||||
|
|
||||||
msgid "footer.copy"
|
|
||||||
msgstr "speedBB"
|
|
||||||
|
|
||||||
msgid "form.title"
|
|
||||||
msgstr "Title"
|
|
||||||
|
|
||||||
msgid "form.body"
|
|
||||||
msgstr "Body"
|
|
||||||
|
|
||||||
msgid "form.message"
|
|
||||||
msgstr "Message"
|
|
||||||
|
|
||||||
msgid "form.email"
|
|
||||||
msgstr "Email"
|
|
||||||
|
|
||||||
msgid "form.username"
|
|
||||||
msgstr "Username"
|
|
||||||
|
|
||||||
msgid "form.password"
|
|
||||||
msgstr "Password"
|
|
||||||
|
|
||||||
msgid "form.thread_title_placeholder"
|
|
||||||
msgstr "Topic headline"
|
|
||||||
|
|
||||||
msgid "form.thread_body_placeholder"
|
|
||||||
msgstr "Share the context and your question."
|
|
||||||
|
|
||||||
msgid "form.reply_placeholder"
|
|
||||||
msgstr "Share your reply."
|
|
||||||
|
|
||||||
msgid "form.posting"
|
|
||||||
msgstr "Posting..."
|
|
||||||
|
|
||||||
msgid "form.create_thread"
|
|
||||||
msgstr "Create thread"
|
|
||||||
|
|
||||||
msgid "form.post_reply"
|
|
||||||
msgstr "Post reply"
|
|
||||||
|
|
||||||
msgid "form.signing_in"
|
|
||||||
msgstr "Signing in..."
|
|
||||||
|
|
||||||
msgid "form.sign_in"
|
|
||||||
msgstr "Sign in"
|
|
||||||
|
|
||||||
msgid "form.registering"
|
|
||||||
msgstr "Registering..."
|
|
||||||
|
|
||||||
msgid "form.create_account"
|
|
||||||
msgstr "Create account"
|
|
||||||
|
|
||||||
msgid "nav.acp"
|
|
||||||
msgstr "ACP"
|
|
||||||
|
|
||||||
msgid "acp.title"
|
|
||||||
msgstr "Admin control panel"
|
|
||||||
|
|
||||||
msgid "acp.no_access"
|
|
||||||
msgstr "You do not have access to this area."
|
|
||||||
|
|
||||||
msgid "acp.general"
|
|
||||||
msgstr "General"
|
|
||||||
|
|
||||||
msgid "acp.general_hint"
|
|
||||||
msgstr "Global settings and board configuration will appear here."
|
|
||||||
|
|
||||||
msgid "acp.forums"
|
|
||||||
msgstr "Forums"
|
|
||||||
|
|
||||||
msgid "acp.forums_hint"
|
|
||||||
msgstr "Manage categories and forums from a tree view."
|
|
||||||
|
|
||||||
msgid "acp.users"
|
|
||||||
msgstr "Users"
|
|
||||||
|
|
||||||
msgid "acp.users_hint"
|
|
||||||
msgstr "User management tools will appear here."
|
|
||||||
|
|
||||||
msgid "acp.forums_tree"
|
|
||||||
msgstr "Forum tree"
|
|
||||||
|
|
||||||
msgid "acp.forums_empty"
|
|
||||||
msgstr "No forums yet. Create the first one on the right."
|
|
||||||
|
|
||||||
msgid "acp.forums_create_title"
|
|
||||||
msgstr "Create forum or category"
|
|
||||||
|
|
||||||
msgid "acp.forums_edit_title"
|
|
||||||
msgstr "Edit forum"
|
|
||||||
|
|
||||||
msgid "acp.forums_type"
|
|
||||||
msgstr "Type"
|
|
||||||
|
|
||||||
msgid "acp.forums_parent"
|
|
||||||
msgstr "Parent category"
|
|
||||||
|
|
||||||
msgid "acp.forums_parent_root"
|
|
||||||
msgstr "Root (no parent)"
|
|
||||||
|
|
||||||
msgid "acp.forums_confirm_delete"
|
|
||||||
msgstr "Delete this forum? This cannot be undone."
|
|
||||||
|
|
||||||
msgid "acp.loading"
|
|
||||||
msgstr "Loading..."
|
|
||||||
|
|
||||||
msgid "acp.refresh"
|
|
||||||
msgstr "Refresh"
|
|
||||||
|
|
||||||
msgid "acp.create"
|
|
||||||
msgstr "Create"
|
|
||||||
|
|
||||||
msgid "acp.save"
|
|
||||||
msgstr "Save"
|
|
||||||
|
|
||||||
msgid "acp.reset"
|
|
||||||
msgstr "Reset"
|
|
||||||
|
|
||||||
msgid "acp.edit"
|
|
||||||
msgstr "Edit"
|
|
||||||
|
|
||||||
msgid "acp.delete"
|
|
||||||
msgstr "Delete"
|
|
||||||
|
|
||||||
msgid "form.description"
|
|
||||||
msgstr "Description"
|
|
||||||
|
|
||||||
msgid "acp.new_category"
|
|
||||||
msgstr "New category"
|
|
||||||
|
|
||||||
msgid "acp.new_forum"
|
|
||||||
msgstr "New forum"
|
|
||||||
|
|
||||||
msgid "acp.forums_form_hint"
|
|
||||||
msgstr "Create a new forum or edit the selected one. Categories can contain forums and other categories."
|
|
||||||
|
|
||||||
msgid "acp.forums_name_required"
|
|
||||||
msgstr "Please enter a name before saving."
|
|
||||||
|
|
||||||
msgid "acp.drag_handle"
|
|
||||||
msgstr "Drag to reorder"
|
|
||||||
|
|
||||||
msgid "acp.expand_all"
|
|
||||||
msgstr "Expand all"
|
|
||||||
|
|
||||||
msgid "acp.collapse_all"
|
|
||||||
msgstr "Collapse all"
|
|
||||||
|
|
||||||
msgid "acp.forums_form_empty_title"
|
|
||||||
msgstr "No selection"
|
|
||||||
|
|
||||||
msgid "acp.forums_form_empty_hint"
|
|
||||||
msgstr "Choose a forum to edit or click New category / New forum to create one."
|
|
||||||
|
|
||||||
msgid "acp.cancel"
|
|
||||||
msgstr "Cancel"
|
|
||||||
40
app/Actions/Fortify/CreateNewUser.php
Normal file
40
app/Actions/Fortify/CreateNewUser.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Fortify;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use Laravel\Fortify\Contracts\CreatesNewUsers;
|
||||||
|
|
||||||
|
class CreateNewUser implements CreatesNewUsers
|
||||||
|
{
|
||||||
|
use PasswordValidationRules;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate and create a newly registered user.
|
||||||
|
*
|
||||||
|
* @param array<string, string> $input
|
||||||
|
*/
|
||||||
|
public function create(array $input): User
|
||||||
|
{
|
||||||
|
Validator::make($input, [
|
||||||
|
'name' => ['required', 'string', 'max:255'],
|
||||||
|
'email' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
'email',
|
||||||
|
'max:255',
|
||||||
|
Rule::unique(User::class),
|
||||||
|
],
|
||||||
|
'password' => $this->passwordRules(),
|
||||||
|
])->validate();
|
||||||
|
|
||||||
|
return User::create([
|
||||||
|
'name' => $input['name'],
|
||||||
|
'email' => $input['email'],
|
||||||
|
'password' => Hash::make($input['password']),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
app/Actions/Fortify/PasswordValidationRules.php
Normal file
18
app/Actions/Fortify/PasswordValidationRules.php
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Fortify;
|
||||||
|
|
||||||
|
use Illuminate\Validation\Rules\Password;
|
||||||
|
|
||||||
|
trait PasswordValidationRules
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the validation rules used to validate passwords.
|
||||||
|
*
|
||||||
|
* @return array<int, \Illuminate\Contracts\Validation\Rule|array<mixed>|string>
|
||||||
|
*/
|
||||||
|
protected function passwordRules(): array
|
||||||
|
{
|
||||||
|
return ['required', 'string', Password::default(), 'confirmed'];
|
||||||
|
}
|
||||||
|
}
|
||||||
29
app/Actions/Fortify/ResetUserPassword.php
Normal file
29
app/Actions/Fortify/ResetUserPassword.php
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Fortify;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Laravel\Fortify\Contracts\ResetsUserPasswords;
|
||||||
|
|
||||||
|
class ResetUserPassword implements ResetsUserPasswords
|
||||||
|
{
|
||||||
|
use PasswordValidationRules;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate and reset the user's forgotten password.
|
||||||
|
*
|
||||||
|
* @param array<string, string> $input
|
||||||
|
*/
|
||||||
|
public function reset(User $user, array $input): void
|
||||||
|
{
|
||||||
|
Validator::make($input, [
|
||||||
|
'password' => $this->passwordRules(),
|
||||||
|
])->validate();
|
||||||
|
|
||||||
|
$user->forceFill([
|
||||||
|
'password' => Hash::make($input['password']),
|
||||||
|
])->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
32
app/Actions/Fortify/UpdateUserPassword.php
Normal file
32
app/Actions/Fortify/UpdateUserPassword.php
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Fortify;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
|
||||||
|
|
||||||
|
class UpdateUserPassword implements UpdatesUserPasswords
|
||||||
|
{
|
||||||
|
use PasswordValidationRules;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate and update the user's password.
|
||||||
|
*
|
||||||
|
* @param array<string, string> $input
|
||||||
|
*/
|
||||||
|
public function update(User $user, array $input): void
|
||||||
|
{
|
||||||
|
Validator::make($input, [
|
||||||
|
'current_password' => ['required', 'string', 'current_password:web'],
|
||||||
|
'password' => $this->passwordRules(),
|
||||||
|
], [
|
||||||
|
'current_password.current_password' => __('The provided password does not match your current password.'),
|
||||||
|
])->validateWithBag('updatePassword');
|
||||||
|
|
||||||
|
$user->forceFill([
|
||||||
|
'password' => Hash::make($input['password']),
|
||||||
|
])->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
58
app/Actions/Fortify/UpdateUserProfileInformation.php
Normal file
58
app/Actions/Fortify/UpdateUserProfileInformation.php
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Fortify;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
|
||||||
|
|
||||||
|
class UpdateUserProfileInformation implements UpdatesUserProfileInformation
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Validate and update the given user's profile information.
|
||||||
|
*
|
||||||
|
* @param array<string, string> $input
|
||||||
|
*/
|
||||||
|
public function update(User $user, array $input): void
|
||||||
|
{
|
||||||
|
Validator::make($input, [
|
||||||
|
'name' => ['required', 'string', 'max:255'],
|
||||||
|
|
||||||
|
'email' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
'email',
|
||||||
|
'max:255',
|
||||||
|
Rule::unique('users')->ignore($user->id),
|
||||||
|
],
|
||||||
|
])->validateWithBag('updateProfileInformation');
|
||||||
|
|
||||||
|
if ($input['email'] !== $user->email &&
|
||||||
|
$user instanceof MustVerifyEmail) {
|
||||||
|
$this->updateVerifiedUser($user, $input);
|
||||||
|
} else {
|
||||||
|
$user->forceFill([
|
||||||
|
'name' => $input['name'],
|
||||||
|
'email' => $input['email'],
|
||||||
|
])->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the given verified user's profile information.
|
||||||
|
*
|
||||||
|
* @param array<string, string> $input
|
||||||
|
*/
|
||||||
|
protected function updateVerifiedUser(User $user, array $input): void
|
||||||
|
{
|
||||||
|
$user->forceFill([
|
||||||
|
'name' => $input['name'],
|
||||||
|
'email' => $input['email'],
|
||||||
|
'email_verified_at' => null,
|
||||||
|
])->save();
|
||||||
|
|
||||||
|
$user->sendEmailVerificationNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
71
app/Http/Controllers/AuthController.php
Normal file
71
app/Http/Controllers/AuthController.php
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Actions\Fortify\CreateNewUser;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
|
||||||
|
class AuthController extends Controller
|
||||||
|
{
|
||||||
|
public function register(Request $request, CreateNewUser $creator): JsonResponse
|
||||||
|
{
|
||||||
|
$input = [
|
||||||
|
'name' => $request->input('name') ?? $request->input('username'),
|
||||||
|
'email' => $request->input('email'),
|
||||||
|
'password' => $request->input('password') ?? $request->input('plainPassword'),
|
||||||
|
'password_confirmation' => $request->input('password_confirmation') ?? $request->input('plainPassword'),
|
||||||
|
];
|
||||||
|
|
||||||
|
$user = $creator->create($input);
|
||||||
|
|
||||||
|
$user->sendEmailVerificationNotification();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'email' => $user->email,
|
||||||
|
'message' => 'Verification email sent.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function login(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'email' => ['required', 'email'],
|
||||||
|
'password' => ['required', 'string'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = User::where('email', $request->input('email'))->first();
|
||||||
|
|
||||||
|
if (!$user || !Hash::check($request->input('password'), $user->password)) {
|
||||||
|
throw ValidationException::withMessages([
|
||||||
|
'email' => ['Invalid credentials.'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$user->hasVerifiedEmail()) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Email not verified.',
|
||||||
|
], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = $user->createToken('api')->plainTextToken;
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'token' => $token,
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'email' => $user->email,
|
||||||
|
'roles' => $user->roles()->pluck('name')->values(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logout(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$request->user()?->currentAccessToken()?->delete();
|
||||||
|
|
||||||
|
return response()->json(null, 204);
|
||||||
|
}
|
||||||
|
}
|
||||||
8
app/Http/Controllers/Controller.php
Normal file
8
app/Http/Controllers/Controller.php
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
abstract class Controller
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
179
app/Http/Controllers/ForumController.php
Normal file
179
app/Http/Controllers/ForumController.php
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Forum;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class ForumController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$query = Forum::query();
|
||||||
|
|
||||||
|
$parentParam = $request->query('parent');
|
||||||
|
if (is_array($parentParam) && array_key_exists('exists', $parentParam)) {
|
||||||
|
$exists = filter_var($parentParam['exists'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
||||||
|
if ($exists === false) {
|
||||||
|
$query->whereNull('parent_id');
|
||||||
|
} elseif ($exists === true) {
|
||||||
|
$query->whereNotNull('parent_id');
|
||||||
|
}
|
||||||
|
} elseif (is_string($parentParam)) {
|
||||||
|
$parentId = $this->parseIriId($parentParam);
|
||||||
|
if ($parentId !== null) {
|
||||||
|
$query->where('parent_id', $parentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->filled('type')) {
|
||||||
|
$query->where('type', $request->query('type'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$forums = $query
|
||||||
|
->orderBy('position')
|
||||||
|
->orderBy('name')
|
||||||
|
->get()
|
||||||
|
->map(fn (Forum $forum) => $this->serializeForum($forum));
|
||||||
|
|
||||||
|
return response()->json($forums);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Forum $forum): JsonResponse
|
||||||
|
{
|
||||||
|
return response()->json($this->serializeForum($forum));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$data = $request->validate([
|
||||||
|
'name' => ['required', 'string', 'max:100'],
|
||||||
|
'description' => ['nullable', 'string'],
|
||||||
|
'type' => ['required', Rule::in(['category', 'forum'])],
|
||||||
|
'parent' => ['nullable', 'string'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$parentId = $this->parseIriId($data['parent'] ?? null);
|
||||||
|
|
||||||
|
if ($parentId) {
|
||||||
|
$parent = Forum::findOrFail($parentId);
|
||||||
|
if ($parent->type !== 'category') {
|
||||||
|
return response()->json(['message' => 'Parent must be a category.'], 422);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$position = Forum::where('parent_id', $parentId)->max('position');
|
||||||
|
|
||||||
|
$forum = Forum::create([
|
||||||
|
'name' => $data['name'],
|
||||||
|
'description' => $data['description'] ?? null,
|
||||||
|
'type' => $data['type'],
|
||||||
|
'parent_id' => $parentId,
|
||||||
|
'position' => ($position ?? 0) + 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json($this->serializeForum($forum), 201);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request, Forum $forum): JsonResponse
|
||||||
|
{
|
||||||
|
$data = $request->validate([
|
||||||
|
'name' => ['sometimes', 'required', 'string', 'max:100'],
|
||||||
|
'description' => ['nullable', 'string'],
|
||||||
|
'type' => ['sometimes', Rule::in(['category', 'forum'])],
|
||||||
|
'parent' => ['nullable', 'string'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$parentId = $this->parseIriId($data['parent'] ?? null);
|
||||||
|
|
||||||
|
if (array_key_exists('parent', $data)) {
|
||||||
|
if ($parentId) {
|
||||||
|
$parent = Forum::findOrFail($parentId);
|
||||||
|
if ($parent->type !== 'category') {
|
||||||
|
return response()->json(['message' => 'Parent must be a category.'], 422);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$forum->parent_id = $parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('name', $data)) {
|
||||||
|
$forum->name = $data['name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('description', $data)) {
|
||||||
|
$forum->description = $data['description'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('type', $data)) {
|
||||||
|
$forum->type = $data['type'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$forum->save();
|
||||||
|
|
||||||
|
return response()->json($this->serializeForum($forum));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Forum $forum): JsonResponse
|
||||||
|
{
|
||||||
|
$forum->delete();
|
||||||
|
|
||||||
|
return response()->json(null, 204);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reorder(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$data = $request->validate([
|
||||||
|
'parentId' => ['nullable'],
|
||||||
|
'orderedIds' => ['required', 'array'],
|
||||||
|
'orderedIds.*' => ['integer'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$parentId = $data['parentId'] ?? null;
|
||||||
|
if ($parentId === '' || $parentId === 'null') {
|
||||||
|
$parentId = null;
|
||||||
|
} elseif ($parentId !== null) {
|
||||||
|
$parentId = (int) $parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($data['orderedIds'] as $index => $forumId) {
|
||||||
|
Forum::where('id', $forumId)
|
||||||
|
->where('parent_id', $parentId)
|
||||||
|
->update(['position' => $index + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(['status' => 'ok']);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseIriId(?string $value): ?int
|
||||||
|
{
|
||||||
|
if (!$value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('#/forums/(\d+)$#', $value, $matches)) {
|
||||||
|
return (int) $matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_numeric($value)) {
|
||||||
|
return (int) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function serializeForum(Forum $forum): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $forum->id,
|
||||||
|
'name' => $forum->name,
|
||||||
|
'description' => $forum->description,
|
||||||
|
'type' => $forum->type,
|
||||||
|
'parent' => $forum->parent_id ? "/api/forums/{$forum->parent_id}" : null,
|
||||||
|
'position' => $forum->position,
|
||||||
|
'created_at' => $forum->created_at?->toIso8601String(),
|
||||||
|
'updated_at' => $forum->updated_at?->toIso8601String(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
22
app/Http/Controllers/I18nController.php
Normal file
22
app/Http/Controllers/I18nController.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
|
||||||
|
class I18nController extends Controller
|
||||||
|
{
|
||||||
|
public function __invoke(string $locale): JsonResponse
|
||||||
|
{
|
||||||
|
$path = resource_path("lang/{$locale}.json");
|
||||||
|
|
||||||
|
if (!File::exists($path)) {
|
||||||
|
return response()->json([], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$contents = File::get($path);
|
||||||
|
|
||||||
|
return response()->json(json_decode($contents, true, 512, JSON_THROW_ON_ERROR));
|
||||||
|
}
|
||||||
|
}
|
||||||
86
app/Http/Controllers/PostController.php
Normal file
86
app/Http/Controllers/PostController.php
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Post;
|
||||||
|
use App\Models\Thread;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class PostController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$query = Post::query();
|
||||||
|
|
||||||
|
$threadParam = $request->query('thread');
|
||||||
|
if (is_string($threadParam)) {
|
||||||
|
$threadId = $this->parseIriId($threadParam);
|
||||||
|
if ($threadId !== null) {
|
||||||
|
$query->where('thread_id', $threadId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$posts = $query
|
||||||
|
->oldest('created_at')
|
||||||
|
->get()
|
||||||
|
->map(fn (Post $post) => $this->serializePost($post));
|
||||||
|
|
||||||
|
return response()->json($posts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$data = $request->validate([
|
||||||
|
'body' => ['required', 'string'],
|
||||||
|
'thread' => ['required', 'string'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$threadId = $this->parseIriId($data['thread']);
|
||||||
|
$thread = Thread::findOrFail($threadId);
|
||||||
|
|
||||||
|
$post = Post::create([
|
||||||
|
'thread_id' => $thread->id,
|
||||||
|
'user_id' => $request->user()?->id,
|
||||||
|
'body' => $data['body'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json($this->serializePost($post), 201);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Post $post): JsonResponse
|
||||||
|
{
|
||||||
|
$post->delete();
|
||||||
|
|
||||||
|
return response()->json(null, 204);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseIriId(?string $value): ?int
|
||||||
|
{
|
||||||
|
if (!$value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('#/threads/(\d+)$#', $value, $matches)) {
|
||||||
|
return (int) $matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_numeric($value)) {
|
||||||
|
return (int) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function serializePost(Post $post): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $post->id,
|
||||||
|
'body' => $post->body,
|
||||||
|
'thread' => "/api/threads/{$post->thread_id}",
|
||||||
|
'user_id' => $post->user_id,
|
||||||
|
'created_at' => $post->created_at?->toIso8601String(),
|
||||||
|
'updated_at' => $post->updated_at?->toIso8601String(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
27
app/Http/Controllers/SettingController.php
Normal file
27
app/Http/Controllers/SettingController.php
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Setting;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class SettingController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$query = Setting::query();
|
||||||
|
|
||||||
|
if ($request->filled('key')) {
|
||||||
|
$query->where('key', $request->query('key'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$settings = $query->get()->map(fn (Setting $setting) => [
|
||||||
|
'id' => $setting->id,
|
||||||
|
'key' => $setting->key,
|
||||||
|
'value' => $setting->value,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json($settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
98
app/Http/Controllers/ThreadController.php
Normal file
98
app/Http/Controllers/ThreadController.php
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Forum;
|
||||||
|
use App\Models\Thread;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class ThreadController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$query = Thread::query();
|
||||||
|
|
||||||
|
$forumParam = $request->query('forum');
|
||||||
|
if (is_string($forumParam)) {
|
||||||
|
$forumId = $this->parseIriId($forumParam);
|
||||||
|
if ($forumId !== null) {
|
||||||
|
$query->where('forum_id', $forumId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$threads = $query
|
||||||
|
->latest('created_at')
|
||||||
|
->get()
|
||||||
|
->map(fn (Thread $thread) => $this->serializeThread($thread));
|
||||||
|
|
||||||
|
return response()->json($threads);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Thread $thread): JsonResponse
|
||||||
|
{
|
||||||
|
return response()->json($this->serializeThread($thread));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$data = $request->validate([
|
||||||
|
'title' => ['required', 'string'],
|
||||||
|
'body' => ['required', 'string'],
|
||||||
|
'forum' => ['required', 'string'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$forumId = $this->parseIriId($data['forum']);
|
||||||
|
$forum = Forum::findOrFail($forumId);
|
||||||
|
|
||||||
|
if ($forum->type !== 'forum') {
|
||||||
|
return response()->json(['message' => 'Threads can only be created inside forums.'], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
$thread = Thread::create([
|
||||||
|
'forum_id' => $forum->id,
|
||||||
|
'user_id' => $request->user()?->id,
|
||||||
|
'title' => $data['title'],
|
||||||
|
'body' => $data['body'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json($this->serializeThread($thread), 201);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy(Thread $thread): JsonResponse
|
||||||
|
{
|
||||||
|
$thread->delete();
|
||||||
|
|
||||||
|
return response()->json(null, 204);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseIriId(?string $value): ?int
|
||||||
|
{
|
||||||
|
if (!$value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('#/forums/(\d+)$#', $value, $matches)) {
|
||||||
|
return (int) $matches[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_numeric($value)) {
|
||||||
|
return (int) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function serializeThread(Thread $thread): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'id' => $thread->id,
|
||||||
|
'title' => $thread->title,
|
||||||
|
'body' => $thread->body,
|
||||||
|
'forum' => "/api/forums/{$thread->forum_id}",
|
||||||
|
'user_id' => $thread->user_id,
|
||||||
|
'created_at' => $thread->created_at?->toIso8601String(),
|
||||||
|
'updated_at' => $thread->updated_at?->toIso8601String(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
25
app/Http/Controllers/UserController.php
Normal file
25
app/Http/Controllers/UserController.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
|
class UserController extends Controller
|
||||||
|
{
|
||||||
|
public function index(): JsonResponse
|
||||||
|
{
|
||||||
|
$users = User::query()
|
||||||
|
->with('roles')
|
||||||
|
->orderBy('id')
|
||||||
|
->get()
|
||||||
|
->map(fn (User $user) => [
|
||||||
|
'id' => $user->id,
|
||||||
|
'name' => $user->name,
|
||||||
|
'email' => $user->email,
|
||||||
|
'roles' => $user->roles->pluck('name')->values(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json($users);
|
||||||
|
}
|
||||||
|
}
|
||||||
20
app/Http/Controllers/VersionController.php
Normal file
20
app/Http/Controllers/VersionController.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Setting;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
|
class VersionController extends Controller
|
||||||
|
{
|
||||||
|
public function __invoke(): JsonResponse
|
||||||
|
{
|
||||||
|
$version = Setting::where('key', 'version')->value('value');
|
||||||
|
$build = Setting::where('key', 'build')->value('value');
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'version' => $version,
|
||||||
|
'build' => $build !== null ? (int) $build : null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
60
app/Models/Forum.php
Normal file
60
app/Models/Forum.php
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $name
|
||||||
|
* @property string|null $description
|
||||||
|
* @property string $type
|
||||||
|
* @property int|null $parent_id
|
||||||
|
* @property int $position
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, Forum> $children
|
||||||
|
* @property-read int|null $children_count
|
||||||
|
* @property-read Forum|null $parent
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Thread> $threads
|
||||||
|
* @property-read int|null $threads_count
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Forum newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Forum newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Forum query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Forum whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Forum whereDescription($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Forum whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Forum whereName($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Forum whereParentId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Forum wherePosition($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Forum whereType($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Forum whereUpdatedAt($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class Forum extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'description',
|
||||||
|
'type',
|
||||||
|
'parent_id',
|
||||||
|
'position',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function parent(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(self::class, 'parent_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function children(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(self::class, 'parent_id')->orderBy('position');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function threads(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Thread::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
45
app/Models/Post.php
Normal file
45
app/Models/Post.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $thread_id
|
||||||
|
* @property int|null $user_id
|
||||||
|
* @property string $body
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \App\Models\Thread $thread
|
||||||
|
* @property-read \App\Models\User|null $user
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereBody($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereThreadId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUpdatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUserId($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class Post extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'thread_id',
|
||||||
|
'user_id',
|
||||||
|
'body',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function thread(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Thread::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
34
app/Models/Role.php
Normal file
34
app/Models/Role.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $name
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $users
|
||||||
|
* @property-read int|null $users_count
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Role newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Role newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Role query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Role whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Role whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Role whereName($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Role whereUpdatedAt($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class Role extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function users(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(User::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
app/Models/Setting.php
Normal file
29
app/Models/Setting.php
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $key
|
||||||
|
* @property string $value
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Setting newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Setting newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Setting query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Setting whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Setting whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Setting whereKey($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Setting whereUpdatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Setting whereValue($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class Setting extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'key',
|
||||||
|
'value',
|
||||||
|
];
|
||||||
|
}
|
||||||
56
app/Models/Thread.php
Normal file
56
app/Models/Thread.php
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $forum_id
|
||||||
|
* @property int|null $user_id
|
||||||
|
* @property string $title
|
||||||
|
* @property string $body
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \App\Models\Forum $forum
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Post> $posts
|
||||||
|
* @property-read int|null $posts_count
|
||||||
|
* @property-read \App\Models\User|null $user
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Thread newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Thread newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Thread query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Thread whereBody($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Thread whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Thread whereForumId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Thread whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Thread whereTitle($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Thread whereUpdatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Thread whereUserId($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class Thread extends Model
|
||||||
|
{
|
||||||
|
protected $fillable = [
|
||||||
|
'forum_id',
|
||||||
|
'user_id',
|
||||||
|
'title',
|
||||||
|
'body',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function forum(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Forum::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function posts(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Post::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
90
app/Models/User.php
Normal file
90
app/Models/User.php
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
use Laravel\Sanctum\HasApiTokens;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string $name
|
||||||
|
* @property string $email
|
||||||
|
* @property \Illuminate\Support\Carbon|null $email_verified_at
|
||||||
|
* @property string $password
|
||||||
|
* @property string|null $two_factor_secret
|
||||||
|
* @property string|null $two_factor_recovery_codes
|
||||||
|
* @property string|null $two_factor_confirmed_at
|
||||||
|
* @property string|null $remember_token
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @property-read \Illuminate\Notifications\DatabaseNotificationCollection<int, \Illuminate\Notifications\DatabaseNotification> $notifications
|
||||||
|
* @property-read int|null $notifications_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Role> $roles
|
||||||
|
* @property-read int|null $roles_count
|
||||||
|
* @property-read \Illuminate\Database\Eloquent\Collection<int, \Laravel\Sanctum\PersonalAccessToken> $tokens
|
||||||
|
* @property-read int|null $tokens_count
|
||||||
|
* @method static \Database\Factories\UserFactory factory($count = null, $state = [])
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereEmail($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereEmailVerifiedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereName($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User wherePassword($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereRememberToken($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereTwoFactorConfirmedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereTwoFactorRecoveryCodes($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereTwoFactorSecret($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|User whereUpdatedAt($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class User extends Authenticatable implements MustVerifyEmail
|
||||||
|
{
|
||||||
|
/** @use HasFactory<\Database\Factories\UserFactory> */
|
||||||
|
use HasApiTokens, HasFactory, Notifiable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that are mass assignable.
|
||||||
|
*
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'email',
|
||||||
|
'password',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that should be hidden for serialization.
|
||||||
|
*
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
protected $hidden = [
|
||||||
|
'password',
|
||||||
|
'remember_token',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attributes that should be cast.
|
||||||
|
*
|
||||||
|
* @return array<string, string>
|
||||||
|
*/
|
||||||
|
protected function casts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'email_verified_at' => 'datetime',
|
||||||
|
'password' => 'hashed',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function roles(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Role::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
24
app/Providers/AppServiceProvider.php
Normal file
24
app/Providers/AppServiceProvider.php
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class AppServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register any application services.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap any application services.
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
48
app/Providers/FortifyServiceProvider.php
Normal file
48
app/Providers/FortifyServiceProvider.php
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Actions\Fortify\CreateNewUser;
|
||||||
|
use App\Actions\Fortify\ResetUserPassword;
|
||||||
|
use App\Actions\Fortify\UpdateUserPassword;
|
||||||
|
use App\Actions\Fortify\UpdateUserProfileInformation;
|
||||||
|
use Illuminate\Cache\RateLimiting\Limit;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\RateLimiter;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Laravel\Fortify\Actions\RedirectIfTwoFactorAuthenticatable;
|
||||||
|
use Laravel\Fortify\Fortify;
|
||||||
|
|
||||||
|
class FortifyServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register any application services.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap any application services.
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
Fortify::createUsersUsing(CreateNewUser::class);
|
||||||
|
Fortify::updateUserProfileInformationUsing(UpdateUserProfileInformation::class);
|
||||||
|
Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
|
||||||
|
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
|
||||||
|
Fortify::redirectUserForTwoFactorAuthenticationUsing(RedirectIfTwoFactorAuthenticatable::class);
|
||||||
|
|
||||||
|
RateLimiter::for('login', function (Request $request) {
|
||||||
|
$throttleKey = Str::transliterate(Str::lower($request->input(Fortify::username())).'|'.$request->ip());
|
||||||
|
|
||||||
|
return Limit::perMinute(5)->by($throttleKey);
|
||||||
|
});
|
||||||
|
|
||||||
|
RateLimiter::for('two-factor', function (Request $request) {
|
||||||
|
return Limit::perMinute(5)->by($request->session()->get('login.id'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
18
artisan
Normal file
18
artisan
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Application;
|
||||||
|
use Symfony\Component\Console\Input\ArgvInput;
|
||||||
|
|
||||||
|
define('LARAVEL_START', microtime(true));
|
||||||
|
|
||||||
|
// Register the Composer autoloader...
|
||||||
|
require __DIR__.'/vendor/autoload.php';
|
||||||
|
|
||||||
|
// Bootstrap Laravel and handle the command...
|
||||||
|
/** @var Application $app */
|
||||||
|
$app = require_once __DIR__.'/bootstrap/app.php';
|
||||||
|
|
||||||
|
$status = $app->handleCommand(new ArgvInput);
|
||||||
|
|
||||||
|
exit($status);
|
||||||
19
bootstrap/app.php
Normal file
19
bootstrap/app.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Application;
|
||||||
|
use Illuminate\Foundation\Configuration\Exceptions;
|
||||||
|
use Illuminate\Foundation\Configuration\Middleware;
|
||||||
|
|
||||||
|
return Application::configure(basePath: dirname(__DIR__))
|
||||||
|
->withRouting(
|
||||||
|
web: __DIR__.'/../routes/web.php',
|
||||||
|
api: __DIR__.'/../routes/api.php',
|
||||||
|
commands: __DIR__.'/../routes/console.php',
|
||||||
|
health: '/up',
|
||||||
|
)
|
||||||
|
->withMiddleware(function (Middleware $middleware): void {
|
||||||
|
//
|
||||||
|
})
|
||||||
|
->withExceptions(function (Exceptions $exceptions): void {
|
||||||
|
//
|
||||||
|
})->create();
|
||||||
65
bootstrap/cache/packages.php
vendored
Normal file
65
bootstrap/cache/packages.php
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<?php return array (
|
||||||
|
'barryvdh/laravel-ide-helper' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'laravel/fortify' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Laravel\\Fortify\\FortifyServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'laravel/pail' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Laravel\\Pail\\PailServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'laravel/sail' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Laravel\\Sail\\SailServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'laravel/sanctum' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Laravel\\Sanctum\\SanctumServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'laravel/tinker' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Laravel\\Tinker\\TinkerServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nesbot/carbon' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Carbon\\Laravel\\ServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nunomaduro/collision' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nunomaduro/termwind' =>
|
||||||
|
array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Termwind\\Laravel\\TermwindServiceProvider',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
275
bootstrap/cache/services.php
vendored
Normal file
275
bootstrap/cache/services.php
vendored
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
<?php return array (
|
||||||
|
'providers' =>
|
||||||
|
array (
|
||||||
|
0 => 'Illuminate\\Auth\\AuthServiceProvider',
|
||||||
|
1 => 'Illuminate\\Broadcasting\\BroadcastServiceProvider',
|
||||||
|
2 => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
|
3 => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
|
4 => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
5 => 'Illuminate\\Concurrency\\ConcurrencyServiceProvider',
|
||||||
|
6 => 'Illuminate\\Cookie\\CookieServiceProvider',
|
||||||
|
7 => 'Illuminate\\Database\\DatabaseServiceProvider',
|
||||||
|
8 => 'Illuminate\\Encryption\\EncryptionServiceProvider',
|
||||||
|
9 => 'Illuminate\\Filesystem\\FilesystemServiceProvider',
|
||||||
|
10 => 'Illuminate\\Foundation\\Providers\\FoundationServiceProvider',
|
||||||
|
11 => 'Illuminate\\Hashing\\HashServiceProvider',
|
||||||
|
12 => 'Illuminate\\Mail\\MailServiceProvider',
|
||||||
|
13 => 'Illuminate\\Notifications\\NotificationServiceProvider',
|
||||||
|
14 => 'Illuminate\\Pagination\\PaginationServiceProvider',
|
||||||
|
15 => 'Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider',
|
||||||
|
16 => 'Illuminate\\Pipeline\\PipelineServiceProvider',
|
||||||
|
17 => 'Illuminate\\Queue\\QueueServiceProvider',
|
||||||
|
18 => 'Illuminate\\Redis\\RedisServiceProvider',
|
||||||
|
19 => 'Illuminate\\Session\\SessionServiceProvider',
|
||||||
|
20 => 'Illuminate\\Translation\\TranslationServiceProvider',
|
||||||
|
21 => 'Illuminate\\Validation\\ValidationServiceProvider',
|
||||||
|
22 => 'Illuminate\\View\\ViewServiceProvider',
|
||||||
|
23 => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
||||||
|
24 => 'Laravel\\Fortify\\FortifyServiceProvider',
|
||||||
|
25 => 'Laravel\\Pail\\PailServiceProvider',
|
||||||
|
26 => 'Laravel\\Sail\\SailServiceProvider',
|
||||||
|
27 => 'Laravel\\Sanctum\\SanctumServiceProvider',
|
||||||
|
28 => 'Laravel\\Tinker\\TinkerServiceProvider',
|
||||||
|
29 => 'Carbon\\Laravel\\ServiceProvider',
|
||||||
|
30 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
|
||||||
|
31 => 'Termwind\\Laravel\\TermwindServiceProvider',
|
||||||
|
32 => 'App\\Providers\\AppServiceProvider',
|
||||||
|
33 => 'App\\Providers\\FortifyServiceProvider',
|
||||||
|
),
|
||||||
|
'eager' =>
|
||||||
|
array (
|
||||||
|
0 => 'Illuminate\\Auth\\AuthServiceProvider',
|
||||||
|
1 => 'Illuminate\\Cookie\\CookieServiceProvider',
|
||||||
|
2 => 'Illuminate\\Database\\DatabaseServiceProvider',
|
||||||
|
3 => 'Illuminate\\Encryption\\EncryptionServiceProvider',
|
||||||
|
4 => 'Illuminate\\Filesystem\\FilesystemServiceProvider',
|
||||||
|
5 => 'Illuminate\\Foundation\\Providers\\FoundationServiceProvider',
|
||||||
|
6 => 'Illuminate\\Notifications\\NotificationServiceProvider',
|
||||||
|
7 => 'Illuminate\\Pagination\\PaginationServiceProvider',
|
||||||
|
8 => 'Illuminate\\Session\\SessionServiceProvider',
|
||||||
|
9 => 'Illuminate\\View\\ViewServiceProvider',
|
||||||
|
10 => 'Laravel\\Fortify\\FortifyServiceProvider',
|
||||||
|
11 => 'Laravel\\Pail\\PailServiceProvider',
|
||||||
|
12 => 'Laravel\\Sanctum\\SanctumServiceProvider',
|
||||||
|
13 => 'Carbon\\Laravel\\ServiceProvider',
|
||||||
|
14 => 'NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider',
|
||||||
|
15 => 'Termwind\\Laravel\\TermwindServiceProvider',
|
||||||
|
16 => 'App\\Providers\\AppServiceProvider',
|
||||||
|
17 => 'App\\Providers\\FortifyServiceProvider',
|
||||||
|
),
|
||||||
|
'deferred' =>
|
||||||
|
array (
|
||||||
|
'Illuminate\\Broadcasting\\BroadcastManager' => 'Illuminate\\Broadcasting\\BroadcastServiceProvider',
|
||||||
|
'Illuminate\\Contracts\\Broadcasting\\Factory' => 'Illuminate\\Broadcasting\\BroadcastServiceProvider',
|
||||||
|
'Illuminate\\Contracts\\Broadcasting\\Broadcaster' => 'Illuminate\\Broadcasting\\BroadcastServiceProvider',
|
||||||
|
'Illuminate\\Bus\\Dispatcher' => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
|
'Illuminate\\Contracts\\Bus\\Dispatcher' => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
|
'Illuminate\\Contracts\\Bus\\QueueingDispatcher' => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
|
'Illuminate\\Bus\\BatchRepository' => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
|
'Illuminate\\Bus\\DatabaseBatchRepository' => 'Illuminate\\Bus\\BusServiceProvider',
|
||||||
|
'cache' => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
|
'cache.store' => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
|
'cache.psr6' => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
|
'memcached.connector' => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
|
'Illuminate\\Cache\\RateLimiter' => 'Illuminate\\Cache\\CacheServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\AboutCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Cache\\Console\\ClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Cache\\Console\\ForgetCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ClearCompiledCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Auth\\Console\\ClearResetsCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ConfigCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ConfigClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ConfigShowCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\DbCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\MonitorCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\PruneCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\ShowCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\TableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\WipeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\DownCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EnvironmentCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EnvironmentDecryptCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EnvironmentEncryptCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EventCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EventClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EventListCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Concurrency\\Console\\InvokeSerializedClosureCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\KeyGenerateCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\OptimizeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\OptimizeClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\PackageDiscoverCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Cache\\Console\\PruneStaleTagsCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\ClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\ListFailedCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\FlushFailedCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\ForgetFailedCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\ListenCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\MonitorCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\PauseCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\PruneBatchesCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\PruneFailedJobsCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\RestartCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\ResumeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\RetryCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\RetryBatchCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\WorkCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ReloadCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\RouteCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\RouteClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\RouteListCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\DumpCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Seeds\\SeedCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Console\\Scheduling\\ScheduleFinishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Console\\Scheduling\\ScheduleListCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Console\\Scheduling\\ScheduleRunCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Console\\Scheduling\\ScheduleClearCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Console\\Scheduling\\ScheduleTestCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Console\\Scheduling\\ScheduleWorkCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Console\\Scheduling\\ScheduleInterruptCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\ShowModelCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\StorageLinkCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\StorageUnlinkCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\UpCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ViewCacheCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ViewClearCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ApiInstallCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\BroadcastingInstallCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Cache\\Console\\CacheTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\CastMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ChannelListCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ChannelMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ClassMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ComponentMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ConfigMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ConfigPublishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ConsoleMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Routing\\Console\\ControllerMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\DocsCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EnumMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EventGenerateCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\EventMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ExceptionMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Factories\\FactoryMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\InterfaceMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\JobMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\JobMiddlewareMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\LangPublishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ListenerMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\MailMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Routing\\Console\\MiddlewareMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ModelMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\NotificationMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Notifications\\Console\\NotificationTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ObserverMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\PolicyMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ProviderMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\FailedTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\TableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Queue\\Console\\BatchesTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\RequestMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ResourceMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\RuleMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ScopeMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Seeds\\SeederMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Session\\Console\\SessionTableCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ServeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\StubPublishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\TestMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\TraitMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\VendorPublishCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Foundation\\Console\\ViewMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'migrator' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'migration.repository' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'migration.creator' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Migrations\\Migrator' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\MigrateCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\FreshCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\InstallCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\RefreshCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\ResetCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\RollbackCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\StatusCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Database\\Console\\Migrations\\MigrateMakeCommand' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'composer' => 'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider',
|
||||||
|
'Illuminate\\Concurrency\\ConcurrencyManager' => 'Illuminate\\Concurrency\\ConcurrencyServiceProvider',
|
||||||
|
'hash' => 'Illuminate\\Hashing\\HashServiceProvider',
|
||||||
|
'hash.driver' => 'Illuminate\\Hashing\\HashServiceProvider',
|
||||||
|
'mail.manager' => 'Illuminate\\Mail\\MailServiceProvider',
|
||||||
|
'mailer' => 'Illuminate\\Mail\\MailServiceProvider',
|
||||||
|
'Illuminate\\Mail\\Markdown' => 'Illuminate\\Mail\\MailServiceProvider',
|
||||||
|
'auth.password' => 'Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider',
|
||||||
|
'auth.password.broker' => 'Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider',
|
||||||
|
'Illuminate\\Contracts\\Pipeline\\Hub' => 'Illuminate\\Pipeline\\PipelineServiceProvider',
|
||||||
|
'pipeline' => 'Illuminate\\Pipeline\\PipelineServiceProvider',
|
||||||
|
'queue' => 'Illuminate\\Queue\\QueueServiceProvider',
|
||||||
|
'queue.connection' => 'Illuminate\\Queue\\QueueServiceProvider',
|
||||||
|
'queue.failer' => 'Illuminate\\Queue\\QueueServiceProvider',
|
||||||
|
'queue.listener' => 'Illuminate\\Queue\\QueueServiceProvider',
|
||||||
|
'queue.worker' => 'Illuminate\\Queue\\QueueServiceProvider',
|
||||||
|
'redis' => 'Illuminate\\Redis\\RedisServiceProvider',
|
||||||
|
'redis.connection' => 'Illuminate\\Redis\\RedisServiceProvider',
|
||||||
|
'translator' => 'Illuminate\\Translation\\TranslationServiceProvider',
|
||||||
|
'translation.loader' => 'Illuminate\\Translation\\TranslationServiceProvider',
|
||||||
|
'validator' => 'Illuminate\\Validation\\ValidationServiceProvider',
|
||||||
|
'validation.presence' => 'Illuminate\\Validation\\ValidationServiceProvider',
|
||||||
|
'Illuminate\\Contracts\\Validation\\UncompromisedVerifier' => 'Illuminate\\Validation\\ValidationServiceProvider',
|
||||||
|
'Barryvdh\\LaravelIdeHelper\\Console\\GeneratorCommand' => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
||||||
|
'Barryvdh\\LaravelIdeHelper\\Console\\ModelsCommand' => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
||||||
|
'Barryvdh\\LaravelIdeHelper\\Console\\MetaCommand' => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
||||||
|
'Barryvdh\\LaravelIdeHelper\\Console\\EloquentCommand' => 'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider',
|
||||||
|
'Laravel\\Sail\\Console\\InstallCommand' => 'Laravel\\Sail\\SailServiceProvider',
|
||||||
|
'Laravel\\Sail\\Console\\PublishCommand' => 'Laravel\\Sail\\SailServiceProvider',
|
||||||
|
'command.tinker' => 'Laravel\\Tinker\\TinkerServiceProvider',
|
||||||
|
),
|
||||||
|
'when' =>
|
||||||
|
array (
|
||||||
|
'Illuminate\\Broadcasting\\BroadcastServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Bus\\BusServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Cache\\CacheServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Foundation\\Providers\\ConsoleSupportServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Concurrency\\ConcurrencyServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Hashing\\HashServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Mail\\MailServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Auth\\Passwords\\PasswordResetServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Pipeline\\PipelineServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Queue\\QueueServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Redis\\RedisServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Translation\\TranslationServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Illuminate\\Validation\\ValidationServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Laravel\\Sail\\SailServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
'Laravel\\Tinker\\TinkerServiceProvider' =>
|
||||||
|
array (
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
6
bootstrap/providers.php
Normal file
6
bootstrap/providers.php
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
App\Providers\AppServiceProvider::class,
|
||||||
|
App\Providers\FortifyServiceProvider::class,
|
||||||
|
];
|
||||||
89
composer.json
Normal file
89
composer.json
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://getcomposer.org/schema.json",
|
||||||
|
"name": "laravel/laravel",
|
||||||
|
"type": "project",
|
||||||
|
"description": "The skeleton application for the Laravel framework.",
|
||||||
|
"keywords": ["laravel", "framework"],
|
||||||
|
"license": "MIT",
|
||||||
|
"require": {
|
||||||
|
"php": "^8.2",
|
||||||
|
"laravel/fortify": "*",
|
||||||
|
"laravel/framework": "^12.0",
|
||||||
|
"laravel/sanctum": "*",
|
||||||
|
"laravel/tinker": "^2.10.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"barryvdh/laravel-ide-helper": "^3.6",
|
||||||
|
"fakerphp/faker": "^1.23",
|
||||||
|
"laravel/pail": "^1.2.2",
|
||||||
|
"laravel/pint": "^1.24",
|
||||||
|
"laravel/sail": "^1.41",
|
||||||
|
"mockery/mockery": "^1.6",
|
||||||
|
"nunomaduro/collision": "^8.6",
|
||||||
|
"phpunit/phpunit": "^11.5.3"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"App\\": "app/",
|
||||||
|
"Database\\Factories\\": "database/factories/",
|
||||||
|
"Database\\Seeders\\": "database/seeders/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"setup": [
|
||||||
|
"composer install",
|
||||||
|
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\"",
|
||||||
|
"@php artisan key:generate",
|
||||||
|
"@php artisan migrate --force",
|
||||||
|
"npm install",
|
||||||
|
"npm run build"
|
||||||
|
],
|
||||||
|
"dev": [
|
||||||
|
"Composer\\Config::disableProcessTimeout",
|
||||||
|
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite --kill-others"
|
||||||
|
],
|
||||||
|
"test": [
|
||||||
|
"@php artisan config:clear --ansi",
|
||||||
|
"@php artisan test"
|
||||||
|
],
|
||||||
|
"post-autoload-dump": [
|
||||||
|
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||||
|
"@php artisan package:discover --ansi"
|
||||||
|
],
|
||||||
|
"post-update-cmd": [
|
||||||
|
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
|
||||||
|
],
|
||||||
|
"post-root-package-install": [
|
||||||
|
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||||
|
],
|
||||||
|
"post-create-project-cmd": [
|
||||||
|
"@php artisan key:generate --ansi",
|
||||||
|
"@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
|
||||||
|
"@php artisan migrate --graceful --ansi"
|
||||||
|
],
|
||||||
|
"pre-package-uninstall": [
|
||||||
|
"Illuminate\\Foundation\\ComposerScripts::prePackageUninstall"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"dont-discover": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"optimize-autoloader": true,
|
||||||
|
"preferred-install": "dist",
|
||||||
|
"sort-packages": true,
|
||||||
|
"allow-plugins": {
|
||||||
|
"pestphp/pest-plugin": true,
|
||||||
|
"php-http/discovery": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"prefer-stable": true
|
||||||
|
}
|
||||||
9019
composer.lock
generated
Normal file
9019
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
126
config/app.php
Normal file
126
config/app.php
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Name
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value is the name of your application, which will be used when the
|
||||||
|
| framework needs to place the application's name in a notification or
|
||||||
|
| other UI elements where an application name needs to be displayed.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'name' => env('APP_NAME', 'Laravel'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Environment
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This value determines the "environment" your application is currently
|
||||||
|
| running in. This may determine how you prefer to configure various
|
||||||
|
| services the application utilizes. Set this in your ".env" file.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'env' => env('APP_ENV', 'production'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Debug Mode
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When your application is in debug mode, detailed error messages with
|
||||||
|
| stack traces will be shown on every error that occurs within your
|
||||||
|
| application. If disabled, a simple generic error page is shown.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'debug' => (bool) env('APP_DEBUG', false),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application URL
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This URL is used by the console to properly generate URLs when using
|
||||||
|
| the Artisan command line tool. You should set this to the root of
|
||||||
|
| the application so that it's available within Artisan commands.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'url' => env('APP_URL', 'http://localhost'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Timezone
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify the default timezone for your application, which
|
||||||
|
| will be used by the PHP date and date-time functions. The timezone
|
||||||
|
| is set to "UTC" by default as it is suitable for most use cases.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'timezone' => 'UTC',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Application Locale Configuration
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The application locale determines the default locale that will be used
|
||||||
|
| by Laravel's translation / localization methods. This option can be
|
||||||
|
| set to any locale for which you plan to have translation strings.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'locale' => env('APP_LOCALE', 'en'),
|
||||||
|
|
||||||
|
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
|
||||||
|
|
||||||
|
'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Encryption Key
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This key is utilized by Laravel's encryption services and should be set
|
||||||
|
| to a random, 32 character string to ensure that all encrypted values
|
||||||
|
| are secure. You should do this prior to deploying the application.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'cipher' => 'AES-256-CBC',
|
||||||
|
|
||||||
|
'key' => env('APP_KEY'),
|
||||||
|
|
||||||
|
'previous_keys' => [
|
||||||
|
...array_filter(
|
||||||
|
explode(',', (string) env('APP_PREVIOUS_KEYS', ''))
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Maintenance Mode Driver
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These configuration options determine the driver used to determine and
|
||||||
|
| manage Laravel's "maintenance mode" status. The "cache" driver will
|
||||||
|
| allow maintenance mode to be controlled across multiple machines.
|
||||||
|
|
|
||||||
|
| Supported drivers: "file", "cache"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'maintenance' => [
|
||||||
|
'driver' => env('APP_MAINTENANCE_DRIVER', 'file'),
|
||||||
|
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
119
config/auth.php
Normal file
119
config/auth.php
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Authentication Defaults
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option defines the default authentication "guard" and password
|
||||||
|
| reset "broker" for your application. You may change these values
|
||||||
|
| as required, but they're a perfect start for most applications.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'defaults' => [
|
||||||
|
'guard' => env('AUTH_GUARD', 'web'),
|
||||||
|
'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Authentication Guards
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Next, you may define every authentication guard for your application.
|
||||||
|
| Of course, a great default configuration has been defined for you
|
||||||
|
| which utilizes session storage plus the Eloquent user provider.
|
||||||
|
|
|
||||||
|
| All authentication guards have a user provider, which defines how the
|
||||||
|
| users are actually retrieved out of your database or other storage
|
||||||
|
| system used by the application. Typically, Eloquent is utilized.
|
||||||
|
|
|
||||||
|
| Supported: "session"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'guards' => [
|
||||||
|
'web' => [
|
||||||
|
'driver' => 'session',
|
||||||
|
'provider' => 'users',
|
||||||
|
],
|
||||||
|
'sanctum' => [
|
||||||
|
'driver' => 'sanctum',
|
||||||
|
'provider' => 'users',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| User Providers
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| All authentication guards have a user provider, which defines how the
|
||||||
|
| users are actually retrieved out of your database or other storage
|
||||||
|
| system used by the application. Typically, Eloquent is utilized.
|
||||||
|
|
|
||||||
|
| If you have multiple user tables or models you may configure multiple
|
||||||
|
| providers to represent the model / table. These providers may then
|
||||||
|
| be assigned to any extra authentication guards you have defined.
|
||||||
|
|
|
||||||
|
| Supported: "database", "eloquent"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'providers' => [
|
||||||
|
'users' => [
|
||||||
|
'driver' => 'eloquent',
|
||||||
|
'model' => env('AUTH_MODEL', App\Models\User::class),
|
||||||
|
],
|
||||||
|
|
||||||
|
// 'users' => [
|
||||||
|
// 'driver' => 'database',
|
||||||
|
// 'table' => 'users',
|
||||||
|
// ],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Resetting Passwords
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| These configuration options specify the behavior of Laravel's password
|
||||||
|
| reset functionality, including the table utilized for token storage
|
||||||
|
| and the user provider that is invoked to actually retrieve users.
|
||||||
|
|
|
||||||
|
| The expiry time is the number of minutes that each reset token will be
|
||||||
|
| considered valid. This security feature keeps tokens short-lived so
|
||||||
|
| they have less time to be guessed. You may change this as needed.
|
||||||
|
|
|
||||||
|
| The throttle setting is the number of seconds a user must wait before
|
||||||
|
| generating more password reset tokens. This prevents the user from
|
||||||
|
| quickly generating a very large amount of password reset tokens.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'passwords' => [
|
||||||
|
'users' => [
|
||||||
|
'provider' => 'users',
|
||||||
|
'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
|
||||||
|
'expire' => 60,
|
||||||
|
'throttle' => 60,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Password Confirmation Timeout
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may define the number of seconds before a password confirmation
|
||||||
|
| window expires and users are asked to re-enter their password via the
|
||||||
|
| confirmation screen. By default, the timeout lasts for three hours.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800),
|
||||||
|
|
||||||
|
];
|
||||||
117
config/cache.php
Normal file
117
config/cache.php
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Cache Store
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option controls the default cache store that will be used by the
|
||||||
|
| framework. This connection is utilized if another isn't explicitly
|
||||||
|
| specified when running a cache operation inside the application.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'default' => env('CACHE_STORE', 'database'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cache Stores
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may define all of the cache "stores" for your application as
|
||||||
|
| well as their drivers. You may even define multiple stores for the
|
||||||
|
| same cache driver to group types of items stored in your caches.
|
||||||
|
|
|
||||||
|
| Supported drivers: "array", "database", "file", "memcached",
|
||||||
|
| "redis", "dynamodb", "octane",
|
||||||
|
| "failover", "null"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'stores' => [
|
||||||
|
|
||||||
|
'array' => [
|
||||||
|
'driver' => 'array',
|
||||||
|
'serialize' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
'database' => [
|
||||||
|
'driver' => 'database',
|
||||||
|
'connection' => env('DB_CACHE_CONNECTION'),
|
||||||
|
'table' => env('DB_CACHE_TABLE', 'cache'),
|
||||||
|
'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'),
|
||||||
|
'lock_table' => env('DB_CACHE_LOCK_TABLE'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'file' => [
|
||||||
|
'driver' => 'file',
|
||||||
|
'path' => storage_path('framework/cache/data'),
|
||||||
|
'lock_path' => storage_path('framework/cache/data'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'memcached' => [
|
||||||
|
'driver' => 'memcached',
|
||||||
|
'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
|
||||||
|
'sasl' => [
|
||||||
|
env('MEMCACHED_USERNAME'),
|
||||||
|
env('MEMCACHED_PASSWORD'),
|
||||||
|
],
|
||||||
|
'options' => [
|
||||||
|
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
|
||||||
|
],
|
||||||
|
'servers' => [
|
||||||
|
[
|
||||||
|
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
|
||||||
|
'port' => env('MEMCACHED_PORT', 11211),
|
||||||
|
'weight' => 100,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'redis' => [
|
||||||
|
'driver' => 'redis',
|
||||||
|
'connection' => env('REDIS_CACHE_CONNECTION', 'cache'),
|
||||||
|
'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'dynamodb' => [
|
||||||
|
'driver' => 'dynamodb',
|
||||||
|
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||||
|
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||||
|
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||||
|
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
|
||||||
|
'endpoint' => env('DYNAMODB_ENDPOINT'),
|
||||||
|
],
|
||||||
|
|
||||||
|
'octane' => [
|
||||||
|
'driver' => 'octane',
|
||||||
|
],
|
||||||
|
|
||||||
|
'failover' => [
|
||||||
|
'driver' => 'failover',
|
||||||
|
'stores' => [
|
||||||
|
'database',
|
||||||
|
'array',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cache Key Prefix
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When utilizing the APC, database, memcached, Redis, and DynamoDB cache
|
||||||
|
| stores, there might be other applications using the same cache. For
|
||||||
|
| that reason, you may prefix every cache key to avoid collisions.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'prefix' => env('CACHE_PREFIX', Str::slug((string) env('APP_NAME', 'laravel')).'-cache-'),
|
||||||
|
|
||||||
|
];
|
||||||
183
config/database.php
Normal file
183
config/database.php
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default Database Connection Name
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may specify which of the database connections below you wish
|
||||||
|
| to use as your default connection for database operations. This is
|
||||||
|
| the connection which will be utilized unless another connection
|
||||||
|
| is explicitly specified when you execute a query / statement.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'default' => env('DB_CONNECTION', 'sqlite'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Database Connections
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Below are all of the database connections defined for your application.
|
||||||
|
| An example configuration is provided for each database system which
|
||||||
|
| is supported by Laravel. You're free to add / remove connections.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'connections' => [
|
||||||
|
|
||||||
|
'sqlite' => [
|
||||||
|
'driver' => 'sqlite',
|
||||||
|
'url' => env('DB_URL'),
|
||||||
|
'database' => env('DB_DATABASE', database_path('database.sqlite')),
|
||||||
|
'prefix' => '',
|
||||||
|
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
|
||||||
|
'busy_timeout' => null,
|
||||||
|
'journal_mode' => null,
|
||||||
|
'synchronous' => null,
|
||||||
|
'transaction_mode' => 'DEFERRED',
|
||||||
|
],
|
||||||
|
|
||||||
|
'mysql' => [
|
||||||
|
'driver' => 'mysql',
|
||||||
|
'url' => env('DB_URL'),
|
||||||
|
'host' => env('DB_HOST', '127.0.0.1'),
|
||||||
|
'port' => env('DB_PORT', '3306'),
|
||||||
|
'database' => env('DB_DATABASE', 'laravel'),
|
||||||
|
'username' => env('DB_USERNAME', 'root'),
|
||||||
|
'password' => env('DB_PASSWORD', ''),
|
||||||
|
'unix_socket' => env('DB_SOCKET', ''),
|
||||||
|
'charset' => env('DB_CHARSET', 'utf8mb4'),
|
||||||
|
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
|
||||||
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
|
'strict' => true,
|
||||||
|
'engine' => null,
|
||||||
|
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||||
|
(PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_CA : \PDO::MYSQL_ATTR_SSL_CA) => env('MYSQL_ATTR_SSL_CA'),
|
||||||
|
]) : [],
|
||||||
|
],
|
||||||
|
|
||||||
|
'mariadb' => [
|
||||||
|
'driver' => 'mariadb',
|
||||||
|
'url' => env('DB_URL'),
|
||||||
|
'host' => env('DB_HOST', '127.0.0.1'),
|
||||||
|
'port' => env('DB_PORT', '3306'),
|
||||||
|
'database' => env('DB_DATABASE', 'laravel'),
|
||||||
|
'username' => env('DB_USERNAME', 'root'),
|
||||||
|
'password' => env('DB_PASSWORD', ''),
|
||||||
|
'unix_socket' => env('DB_SOCKET', ''),
|
||||||
|
'charset' => env('DB_CHARSET', 'utf8mb4'),
|
||||||
|
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
|
||||||
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
|
'strict' => true,
|
||||||
|
'engine' => null,
|
||||||
|
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||||
|
(PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_CA : \PDO::MYSQL_ATTR_SSL_CA) => env('MYSQL_ATTR_SSL_CA'),
|
||||||
|
]) : [],
|
||||||
|
],
|
||||||
|
|
||||||
|
'pgsql' => [
|
||||||
|
'driver' => 'pgsql',
|
||||||
|
'url' => env('DB_URL'),
|
||||||
|
'host' => env('DB_HOST', '127.0.0.1'),
|
||||||
|
'port' => env('DB_PORT', '5432'),
|
||||||
|
'database' => env('DB_DATABASE', 'laravel'),
|
||||||
|
'username' => env('DB_USERNAME', 'root'),
|
||||||
|
'password' => env('DB_PASSWORD', ''),
|
||||||
|
'charset' => env('DB_CHARSET', 'utf8'),
|
||||||
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
|
'search_path' => 'public',
|
||||||
|
'sslmode' => 'prefer',
|
||||||
|
],
|
||||||
|
|
||||||
|
'sqlsrv' => [
|
||||||
|
'driver' => 'sqlsrv',
|
||||||
|
'url' => env('DB_URL'),
|
||||||
|
'host' => env('DB_HOST', 'localhost'),
|
||||||
|
'port' => env('DB_PORT', '1433'),
|
||||||
|
'database' => env('DB_DATABASE', 'laravel'),
|
||||||
|
'username' => env('DB_USERNAME', 'root'),
|
||||||
|
'password' => env('DB_PASSWORD', ''),
|
||||||
|
'charset' => env('DB_CHARSET', 'utf8'),
|
||||||
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
|
// 'encrypt' => env('DB_ENCRYPT', 'yes'),
|
||||||
|
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Migration Repository Table
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This table keeps track of all the migrations that have already run for
|
||||||
|
| your application. Using this information, we can determine which of
|
||||||
|
| the migrations on disk haven't actually been run on the database.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'migrations' => [
|
||||||
|
'table' => 'migrations',
|
||||||
|
'update_date_on_publish' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Redis Databases
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Redis is an open source, fast, and advanced key-value store that also
|
||||||
|
| provides a richer body of commands than a typical key-value system
|
||||||
|
| such as Memcached. You may define your connection settings here.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'redis' => [
|
||||||
|
|
||||||
|
'client' => env('REDIS_CLIENT', 'phpredis'),
|
||||||
|
|
||||||
|
'options' => [
|
||||||
|
'cluster' => env('REDIS_CLUSTER', 'redis'),
|
||||||
|
'prefix' => env('REDIS_PREFIX', Str::slug((string) env('APP_NAME', 'laravel')).'-database-'),
|
||||||
|
'persistent' => env('REDIS_PERSISTENT', false),
|
||||||
|
],
|
||||||
|
|
||||||
|
'default' => [
|
||||||
|
'url' => env('REDIS_URL'),
|
||||||
|
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||||
|
'username' => env('REDIS_USERNAME'),
|
||||||
|
'password' => env('REDIS_PASSWORD'),
|
||||||
|
'port' => env('REDIS_PORT', '6379'),
|
||||||
|
'database' => env('REDIS_DB', '0'),
|
||||||
|
'max_retries' => env('REDIS_MAX_RETRIES', 3),
|
||||||
|
'backoff_algorithm' => env('REDIS_BACKOFF_ALGORITHM', 'decorrelated_jitter'),
|
||||||
|
'backoff_base' => env('REDIS_BACKOFF_BASE', 100),
|
||||||
|
'backoff_cap' => env('REDIS_BACKOFF_CAP', 1000),
|
||||||
|
],
|
||||||
|
|
||||||
|
'cache' => [
|
||||||
|
'url' => env('REDIS_URL'),
|
||||||
|
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||||
|
'username' => env('REDIS_USERNAME'),
|
||||||
|
'password' => env('REDIS_PASSWORD'),
|
||||||
|
'port' => env('REDIS_PORT', '6379'),
|
||||||
|
'database' => env('REDIS_CACHE_DB', '1'),
|
||||||
|
'max_retries' => env('REDIS_MAX_RETRIES', 3),
|
||||||
|
'backoff_algorithm' => env('REDIS_BACKOFF_ALGORITHM', 'decorrelated_jitter'),
|
||||||
|
'backoff_base' => env('REDIS_BACKOFF_BASE', 100),
|
||||||
|
'backoff_cap' => env('REDIS_BACKOFF_CAP', 1000),
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user