Compare commits
3 Commits
462bce226d
...
feature/re
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d5ee292a9 | |||
| 6f53c7ea6f | |||
| 7d9b6793d3 |
27
.env.example
27
.env.example
@@ -3,7 +3,6 @@ APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
APP_URL_API="${APP_URL}/api/"
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
@@ -30,7 +29,7 @@ REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=mailhog
|
||||
MAIL_HOST=mailpit
|
||||
MAIL_PORT=1025
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
@@ -38,24 +37,11 @@ MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS="hello@example.com"
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
AWS_PUBLIC_ACCESS_KEY_ID=
|
||||
AWS_PUBLIC_SECRET_ACCESS_KEY=
|
||||
AWS_PUBLIC_DEFAULT_REGION="us-west-002"
|
||||
AWS_PUBLIC_BUCKET=
|
||||
AWS_PUBLIC_USE_PATH_STYLE_ENDPOINT=false
|
||||
AWS_PUBLIC_ENDPOINT=
|
||||
AWS_PUBLIC_URL=
|
||||
|
||||
AWS_PRIVATE_ACCESS_KEY_ID=
|
||||
AWS_PRIVATE_SECRET_ACCESS_KEY=
|
||||
AWS_PRIVATE_DEFAULT_REGION="us-west-002"
|
||||
AWS_PRIVATE_BUCKET=
|
||||
AWS_PRIVATE_USE_PATH_STYLE_ENDPOINT=false
|
||||
AWS_PRIVATE_ENDPOINT=
|
||||
AWS_PRIVATE_URL=
|
||||
|
||||
CLOUDFLARE_ZONE_ID=
|
||||
CLOUDFLARE_API_KEY=
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||
|
||||
PUSHER_APP_ID=
|
||||
PUSHER_APP_KEY=
|
||||
@@ -65,6 +51,7 @@ PUSHER_PORT=443
|
||||
PUSHER_SCHEME=https
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
VITE_PUSHER_HOST="${PUSHER_HOST}"
|
||||
VITE_PUSHER_PORT="${PUSHER_PORT}"
|
||||
|
||||
59
.env.testing
59
.env.testing
@@ -1,59 +0,0 @@
|
||||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://127.0.0.1
|
||||
APP_URL_API="${APP_URL}/api/"
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=sqlite
|
||||
DB_DATABASE=:memory:
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=array
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=log
|
||||
MAIL_HOST=null
|
||||
MAIL_PORT=null
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=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
|
||||
|
||||
PUSHER_APP_ID=
|
||||
PUSHER_APP_KEY=
|
||||
PUSHER_APP_SECRET=
|
||||
PUSHER_HOST=
|
||||
PUSHER_PORT=443
|
||||
PUSHER_SCHEME=https
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
|
||||
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
VITE_PUSHER_HOST="${PUSHER_HOST}"
|
||||
VITE_PUSHER_PORT="${PUSHER_PORT}"
|
||||
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
|
||||
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
||||
CONTACT_ADDRESS="hello@stemmechanics.com.au"
|
||||
CONTACT_SUBJECT="Contact from website"
|
||||
|
||||
STORAGE_LOCAL_URL="${APP_URL}/api/media/%ID%/download"
|
||||
STORAGE_PUBLIC_URL="${APP_URL}/uploads/%NAME%"
|
||||
@@ -1,3 +0,0 @@
|
||||
.github/
|
||||
.vscode/
|
||||
vendor/
|
||||
22
.eslintrc.js
22
.eslintrc.js
@@ -1,22 +0,0 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:vue/vue3-strongly-recommended",
|
||||
"prettier",
|
||||
"plugin:jsdoc/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
],
|
||||
rules: {
|
||||
"vue/multi-word-component-names": "off",
|
||||
indent: ["off", 4, { ignoredNodes: ["ConditionalExpression"] }],
|
||||
"@typescript-eslint/no-inferrable-types": "off",
|
||||
},
|
||||
plugins: ["jsdoc", "@typescript-eslint"],
|
||||
parser: "vue-eslint-parser",
|
||||
parserOptions: {
|
||||
parser: "@typescript-eslint/parser",
|
||||
},
|
||||
};
|
||||
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,4 +1,4 @@
|
||||
* text=auto
|
||||
* text=auto eol=lf
|
||||
|
||||
*.blade.php diff=html
|
||||
*.css diff=css
|
||||
|
||||
15
.github/dependabot.yml
vendored
15
.github/dependabot.yml
vendored
@@ -1,15 +0,0 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "composer"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
42
.github/workflows/laravel.yml
vendored
42
.github/workflows/laravel.yml
vendored
@@ -1,42 +0,0 @@
|
||||
name: Laravel
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
laravel-tests:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "8.1"
|
||||
- uses: actions/checkout@v3
|
||||
- name: Copy .env
|
||||
run: php -r "file_exists('.env') || copy('.env.example', '.env');"
|
||||
- name: Install Dependencies
|
||||
run: composer install -q --no-interaction --no-progress --prefer-dist
|
||||
- name: Generate key
|
||||
run: php artisan key:generate
|
||||
- name: Directory Permissions
|
||||
run: chmod -R 777 storage bootstrap/cache
|
||||
- name: Create Database
|
||||
run: |
|
||||
mkdir -p database
|
||||
touch database/database.sqlite
|
||||
- name: Execute tests (Unit and Feature tests) via PHPUnit
|
||||
env:
|
||||
DB_CONNECTION: sqlite
|
||||
DB_DATABASE: database/database.sqlite
|
||||
run: vendor/bin/phpunit
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "16.x"
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Run Vue tests
|
||||
env:
|
||||
LARAVEL_BYPASS_ENV_CHECK: "1"
|
||||
run: npm run test
|
||||
272
.gitignore
vendored
272
.gitignore
vendored
@@ -1,258 +1,20 @@
|
||||
### Composer ###
|
||||
composer.phar
|
||||
/vendor/
|
||||
|
||||
# composer.lock
|
||||
|
||||
### Laravel ###
|
||||
node_modules/
|
||||
/.phpunit.cache
|
||||
/node_modules
|
||||
/public/build
|
||||
/public/hot
|
||||
/public/storage
|
||||
/storage/*.key
|
||||
/vendor
|
||||
.env
|
||||
.env.backup
|
||||
.env.production
|
||||
.phpunit.result.cache
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
auth.json
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# Laravel 4 specific
|
||||
bootstrap/compiled.php
|
||||
app/storage/
|
||||
|
||||
# Laravel 5 & Lumen specific
|
||||
public/storage
|
||||
public/hot
|
||||
|
||||
# Laravel 5 & Lumen specific with changed public path
|
||||
public_html/storage
|
||||
public_html/hot
|
||||
|
||||
storage/*.key
|
||||
.env
|
||||
Homestead.yaml
|
||||
Homestead.json
|
||||
/.vagrant
|
||||
/.phpunit.cache
|
||||
|
||||
### macOS ###
|
||||
# General
|
||||
/.fleet
|
||||
/.idea
|
||||
/.vscode
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
### macOS Patch ###
|
||||
# iCloud generated files
|
||||
*.icloud
|
||||
|
||||
### Node ###
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
### Node Patch ###
|
||||
# Serverless Webpack directories
|
||||
.webpack/
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
# SvelteKit build / generate output
|
||||
.svelte-kit
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
.ionide
|
||||
|
||||
### Vue ###
|
||||
# gitignore template for Vue.js projects
|
||||
#
|
||||
# Recommended template: Node.gitignore
|
||||
|
||||
# TODO: where does this rule come from?
|
||||
docs/_book
|
||||
|
||||
# TODO: where does this rule come from?
|
||||
test/
|
||||
|
||||
### Vuejs ###
|
||||
# Recommended template: Node.gitignore
|
||||
|
||||
dist/
|
||||
|
||||
### This Project ###
|
||||
/public/uploads
|
||||
/public/build
|
||||
*.key
|
||||
|
||||
### TinyMCE ###
|
||||
/public/tinymce
|
||||
!/public/tinymce/skins/ui/stemmech/
|
||||
|
||||
### Synk ###
|
||||
.dccache
|
||||
|
||||
### TempCodeRunner ###
|
||||
tempCodeRunnerFile.*
|
||||
|
||||
### PHPUnit ###
|
||||
.phpunit.result.cache
|
||||
.gitignore
|
||||
|
||||
### Codesniffer ###
|
||||
phpcs.phar
|
||||
phpcbf.phar
|
||||
|
||||
14
.ls-lint.yml
14
.ls-lint.yml
@@ -1,14 +0,0 @@
|
||||
ls:
|
||||
resources/js/store:
|
||||
.ts: pascalcase
|
||||
"*":
|
||||
.js: camelcase
|
||||
.ts: camelcase
|
||||
.vue: pascalcase
|
||||
.dir: snakecase
|
||||
.type.ts: camelcase
|
||||
ignore:
|
||||
- node_modules
|
||||
- vendor
|
||||
- public/build
|
||||
- public/tinymce
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"bracketSameLine": true,
|
||||
"tabWidth": 4,
|
||||
"htmlWhitespaceSensitivity": "css"
|
||||
}
|
||||
21
.vscode/settings.json
vendored
21
.vscode/settings.json
vendored
@@ -1,20 +1,5 @@
|
||||
{
|
||||
"editor.formatOnType": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
// "source.organizeImports": true // <-- when enabled, breaks tinymce required import order
|
||||
},
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"[vue]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[php]": {
|
||||
// "editor.defaultFormatter": "bmewburn.vscode-intelephense-client"
|
||||
"editor.defaultFormatter": "wongjn.php-sniffer"
|
||||
},
|
||||
"cSpell.words": ["TIMESTAMPDIFF"]
|
||||
"files.associations": {
|
||||
"*.css": "tailwindcss"
|
||||
}
|
||||
}
|
||||
|
||||
18
README.md
18
README.md
@@ -1,7 +1,7 @@
|
||||
<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://travis-ci.org/laravel/framework"><img src="https://travis-ci.org/laravel/framework.svg" alt="Build Status"></a>
|
||||
<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>
|
||||
@@ -31,23 +31,23 @@ If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Lar
|
||||
|
||||
## 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 [Patreon page](https://patreon.com/taylorotwell).
|
||||
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)**
|
||||
- **[WebReinvent](https://webreinvent.com/)**
|
||||
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
|
||||
- **[64 Robots](https://64robots.com)**
|
||||
- **[Cubet Techno Labs](https://cubettech.com)**
|
||||
- **[Cyber-Duck](https://cyber-duck.co.uk)**
|
||||
- **[Many](https://www.many.co.uk)**
|
||||
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
|
||||
- **[DevSquad](https://devsquad.com)**
|
||||
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
|
||||
- **[Cyber-Duck](https://cyber-duck.co.uk)**
|
||||
- **[DevSquad](https://devsquad.com/hire-laravel-developers)**
|
||||
- **[Jump24](https://jump24.co.uk)**
|
||||
- **[Redberry](https://redberry.international/laravel/)**
|
||||
- **[Active Logic](https://activelogic.com)**
|
||||
- **[byte5](https://byte5.de)**
|
||||
- **[OP.GG](https://op.gg)**
|
||||
- **[WebReinvent](https://webreinvent.com/?utm_source=laravel&utm_medium=github&utm_campaign=patreon-sponsors)**
|
||||
- **[Lendio](https://lendio.com)**
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
23355
_ide_helper.php
23355
_ide_helper.php
File diff suppressed because it is too large
Load Diff
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Conductors;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AnalyticsConductor extends Conductor
|
||||
{
|
||||
/**
|
||||
* The Model Class
|
||||
* @var string
|
||||
*/
|
||||
protected $class = \App\Models\AnalyticsSession::class;
|
||||
|
||||
/**
|
||||
* The default includes to include in a request.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $includes = ['requests.type','requests.path'];
|
||||
|
||||
|
||||
/**
|
||||
* Return if the current model is visible.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow model to be visible.
|
||||
*/
|
||||
public static function viewable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/analytics') === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is creatable.
|
||||
*
|
||||
* @return boolean Allow creating model.
|
||||
*/
|
||||
public static function creatable(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is updatable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow updating model.
|
||||
*/
|
||||
public static function updatable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/analytics') === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is destroyable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow deleting model.
|
||||
*/
|
||||
public static function destroyable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/analytics') === true);
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Conductors;
|
||||
|
||||
use App\Models\Media;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\InvalidCastException;
|
||||
use Illuminate\Database\Eloquent\MissingAttributeException;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use LogicException;
|
||||
|
||||
class ArticleConductor extends Conductor
|
||||
{
|
||||
/**
|
||||
* The Model Class
|
||||
* @var string
|
||||
*/
|
||||
protected $class = \App\Models\Article::class;
|
||||
|
||||
/**
|
||||
* The default sorting field
|
||||
* @var string
|
||||
*/
|
||||
protected $sort = '-publish_at';
|
||||
|
||||
/**
|
||||
* The included fields
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $includes = ['attachments', 'user', 'gallery'];
|
||||
|
||||
|
||||
/**
|
||||
* Run a scope query on the collection before anything else.
|
||||
*
|
||||
* @param Builder $builder The builder in use.
|
||||
* @return void
|
||||
*/
|
||||
public function scope(Builder $builder): void
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
if ($user === null || $user->hasPermission('admin/articles') === false) {
|
||||
$builder
|
||||
->where('publish_at', '<=', now());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is visible.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow model to be visible.
|
||||
*/
|
||||
public static function viewable(Model $model): bool
|
||||
{
|
||||
if (Carbon::parse($model->publish_at)->isFuture() === true) {
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
if ($user === null || $user->hasPermission('admin/articles') === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is creatable.
|
||||
*
|
||||
* @return boolean Allow creating model.
|
||||
*/
|
||||
public static function creatable(): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/articles') === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is updatable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow updating model.
|
||||
*/
|
||||
public static function updatable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/articles') === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is destroyable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow deleting model.
|
||||
*/
|
||||
public static function destroyable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/articles') === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the final model data
|
||||
*
|
||||
* @param array $data The model data to transform.
|
||||
* @return array The transformed model.
|
||||
*/
|
||||
public function transformFinal(array $data): array
|
||||
{
|
||||
unset($data['user_id']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include Attachments Field.
|
||||
*
|
||||
* @param Model $model Them model.
|
||||
* @return mixed The model result.
|
||||
*/
|
||||
public function includeAttachments(Model $model)
|
||||
{
|
||||
return $model->getAttachments()->map(function ($attachment) {
|
||||
return MediaConductor::includeModel(request(), 'attachments', $attachment->media);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Include Gallery Field.
|
||||
*
|
||||
* @param Model $model Them model.
|
||||
* @return mixed The model result.
|
||||
*/
|
||||
public function includeGallery(Model $model)
|
||||
{
|
||||
return $model->getGallery()->map(function ($item) {
|
||||
return MediaConductor::includeModel(request(), 'gallery', $item->media);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Include User Field.
|
||||
*
|
||||
* @param Model $model Them model.
|
||||
* @return mixed The model result.
|
||||
*/
|
||||
public function includeUser(Model $model)
|
||||
{
|
||||
$cacheKey = "user:{$model['user_id']}";
|
||||
$user = Cache::remember($cacheKey, now()->addDays(28), function () use ($model) {
|
||||
return User::find($model['user_id']);
|
||||
});
|
||||
|
||||
return UserConductor::includeModel(request(), 'user', $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the Hero field.
|
||||
*
|
||||
* @param mixed $value The current value.
|
||||
* @return array|null The new value.
|
||||
*/
|
||||
public function transformHero(mixed $value): array|null
|
||||
{
|
||||
$cacheKey = "media:{$value}";
|
||||
$media = Cache::remember($cacheKey, now()->addDays(28), function () use ($value) {
|
||||
return Media::find($value);
|
||||
});
|
||||
|
||||
return MediaConductor::includeModel(request(), 'hero', $media);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,140 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Conductors;
|
||||
|
||||
use App\Models\Media;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\InvalidCastException;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class EventConductor extends Conductor
|
||||
{
|
||||
/**
|
||||
* The Model Class
|
||||
* @var string
|
||||
*/
|
||||
protected $class = \App\Models\Event::class;
|
||||
|
||||
/**
|
||||
* The default sorting field
|
||||
* @var string
|
||||
*/
|
||||
protected $sort = '-start_at';
|
||||
|
||||
/**
|
||||
* The included fields
|
||||
* @var string[]
|
||||
*/
|
||||
protected $includes = ['attachments'];
|
||||
|
||||
|
||||
/**
|
||||
* Run a scope query on the collection before anything else.
|
||||
*
|
||||
* @param Builder $builder The builder in use.
|
||||
* @return void
|
||||
*/
|
||||
public function scope(Builder $builder): void
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
if ($user === null || $user->hasPermission('admin/events') === false) {
|
||||
$builder
|
||||
->where('status', '!=', 'draft')
|
||||
->where('publish_at', '<=', now());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is visible.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow model to be visible.
|
||||
*/
|
||||
public static function viewable(Model $model): bool
|
||||
{
|
||||
if (strtolower($model->status) === 'draft' || Carbon::parse($model->publish_at)->isFuture() === true) {
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
if ($user === null || $user->hasPermission('admin/events') === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is creatable.
|
||||
*
|
||||
* @return boolean Allow creating model.
|
||||
*/
|
||||
public static function creatable(): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/events') === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is updatable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow updating model.
|
||||
*/
|
||||
public static function updatable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/events') === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is destroyable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow deleting model.
|
||||
*/
|
||||
public static function destroyable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/events') === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Include Attachments Field.
|
||||
*
|
||||
* @param Model $model Them model.
|
||||
* @return mixed The model result.
|
||||
*/
|
||||
public function includeAttachments(Model $model)
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
|
||||
return $model->getAttachments()->map(function ($attachment) use ($user) {
|
||||
if ($attachment->private === false || ($user !== null && $user->hasPermission('admin/events') === true)) {
|
||||
return MediaConductor::includeModel(request(), 'attachments', $attachment->media);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the Hero field.
|
||||
*
|
||||
* @param mixed $value The current value.
|
||||
* @return array|null The new value.
|
||||
*/
|
||||
public function transformHero(mixed $value): array|null
|
||||
{
|
||||
$cacheKey = "media:{$value}";
|
||||
$media = Cache::remember($cacheKey, now()->addDays(28), function () use ($value) {
|
||||
return Media::find($value);
|
||||
});
|
||||
|
||||
return MediaConductor::includeModel(request(), 'hero', $media);
|
||||
}
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Conductors;
|
||||
|
||||
use App\Models\MediaJob;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class MediaConductor extends Conductor
|
||||
{
|
||||
/**
|
||||
* The Model Class
|
||||
* @var string
|
||||
*/
|
||||
protected $class = \App\Models\Media::class;
|
||||
|
||||
/**
|
||||
* The default sorting field
|
||||
* @var string
|
||||
*/
|
||||
protected $sort = 'created_at';
|
||||
|
||||
/**
|
||||
* The included fields
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $includes = ['user', 'jobs'];
|
||||
|
||||
/**
|
||||
* The default filters to use in a request.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
// protected $defaultFilters = [
|
||||
// 'status' => 'OK'
|
||||
// ];
|
||||
|
||||
|
||||
/**
|
||||
* Return an array of model fields visible to the current user.
|
||||
*
|
||||
* @param Model $model The model in question.
|
||||
* @return array The array of field names.
|
||||
*/
|
||||
public function fields(Model $model): array
|
||||
{
|
||||
$fields = parent::fields($model);
|
||||
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
if ($user === null || $user->hasPermission('admin/media') === false) {
|
||||
$fields = arrayRemoveItem($fields, ['security_data', 'storage']);
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a scope query on the collection before anything else.
|
||||
*
|
||||
* @param Builder $builder The builder in use.
|
||||
* @return void
|
||||
*/
|
||||
public function scope(Builder $builder): void
|
||||
{
|
||||
$user = auth()->user();
|
||||
if ($user === null) {
|
||||
$builder->where('security_type', '')
|
||||
->orWhere('security_type', 'password');
|
||||
} else {
|
||||
$builder->where(function ($query) use ($user) {
|
||||
$query->where('security_type', '')
|
||||
->orWhere('security_type', 'password')
|
||||
->orWhere(function ($subquery) use ($user) {
|
||||
$subquery->where('security_type', 'permission')
|
||||
->whereIn('security_data', $user->permissions);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is visible.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow model to be visible.
|
||||
*/
|
||||
public static function viewable(Model $model): bool
|
||||
{
|
||||
if (strcasecmp('permission', $model->security_type) === 0) {
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
if ($user === null || $user->hasPermission($model->security_data) === false) {
|
||||
return false;
|
||||
}
|
||||
} elseif ($model->security_type !== '' && strcasecmp('password', $model->security_type) !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is creatable.
|
||||
*
|
||||
* @return boolean Allow creating model.
|
||||
*/
|
||||
public static function creatable(): bool
|
||||
{
|
||||
$user = auth()->user();
|
||||
return ($user !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is updatable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow updating model.
|
||||
*/
|
||||
public static function updatable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && (strcasecmp($model->user_id, $user->id) === 0 ||
|
||||
$user->hasPermission('admin/media') === true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is destroyable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow deleting model.
|
||||
*/
|
||||
public static function destroyable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && ($model->user_id === $user->id || $user->hasPermission('admin/media') === true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the final model data
|
||||
*
|
||||
* @param array $data The model data to transform.
|
||||
* @return array The transformed model.
|
||||
*/
|
||||
public function transformFinal(array $data): array
|
||||
{
|
||||
unset($data['user_id']);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include User Field.
|
||||
*
|
||||
* @param Model $model Them model.
|
||||
* @return mixed The model result.
|
||||
*/
|
||||
public function includeUser(Model $model)
|
||||
{
|
||||
$user = Cache::remember("user:{$model['user_id']}", now()->addDays(28), function () use ($model) {
|
||||
return User::find($model['user_id']);
|
||||
});
|
||||
|
||||
return UserConductor::includeModel(request(), 'user', $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Include job models in Media
|
||||
*
|
||||
* @param Model $model The reference model.
|
||||
* @return mixed
|
||||
*/
|
||||
public function includeJobs(Model $model)
|
||||
{
|
||||
$jobs = $model->jobs()
|
||||
->select(['id','created_at','updated_at','user_id','status','status_text','progress'])
|
||||
->orderBy('created_at', 'desc')->get();
|
||||
return $jobs;
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Conductors;
|
||||
|
||||
use App\Models\MediaJob;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class MediaJobConductor extends Conductor
|
||||
{
|
||||
/**
|
||||
* The Model Class
|
||||
* @var string
|
||||
*/
|
||||
protected $class = \App\Models\MediaJob::class;
|
||||
|
||||
/**
|
||||
* The default sorting field
|
||||
* @var string
|
||||
*/
|
||||
protected $sort = 'created_at';
|
||||
|
||||
/**
|
||||
* The included fields
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $includes = ['user'];
|
||||
|
||||
|
||||
/**
|
||||
* Return if the current model is creatable.
|
||||
*
|
||||
* @return boolean Allow creating model.
|
||||
*/
|
||||
public static function creatable(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is updatable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow updating model.
|
||||
*/
|
||||
public static function updatable(Model $model): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is destroyable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow deleting model.
|
||||
*/
|
||||
public static function destroyable(Model $model): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the final model data
|
||||
*
|
||||
* @param array $data The model data to transform.
|
||||
* @return array The transformed model.
|
||||
*/
|
||||
public function transformFinal(array $data): array
|
||||
{
|
||||
unset($data['user_id']);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Conductors;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ShortlinkConductor extends Conductor
|
||||
{
|
||||
/**
|
||||
* The Model Class
|
||||
* @var string
|
||||
*/
|
||||
protected $class = \App\Models\Shortlink::class;
|
||||
|
||||
/**
|
||||
* The default sorting field
|
||||
* @var string
|
||||
*/
|
||||
protected $sort = 'created_at';
|
||||
|
||||
|
||||
/**
|
||||
* Return if the current model is creatable.
|
||||
*
|
||||
* @return boolean Allow creating model.
|
||||
*/
|
||||
public static function creatable(): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/shortlinks') === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is updatable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow updating model.
|
||||
*/
|
||||
public static function updatable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/shortlinks') === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is destroyable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow deleting model.
|
||||
*/
|
||||
public static function destroyable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/shortlinks') === true);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Conductors;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class SubscriptionConductor extends Conductor
|
||||
{
|
||||
/**
|
||||
* The Model Class
|
||||
* @var string
|
||||
*/
|
||||
protected $class = \App\Models\Subscription::class;
|
||||
|
||||
|
||||
/**
|
||||
* Return if the current model is updatable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow updating model.
|
||||
*/
|
||||
public static function updatable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && (
|
||||
(strcasecmp($model->email, $user->email) === 0 && $user->email_verified_at !== null) ||
|
||||
$user->hasPermission('admin/subscriptions') === true
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is destroyable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow deleting model.
|
||||
*/
|
||||
public static function destroyable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && ((strcasecmp($model->email, $user->email) === 0 &&
|
||||
$user->email_verified_at !== null) || $user->hasPermission('admin/subscriptions') === true));
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Conductors;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class UserConductor extends Conductor
|
||||
{
|
||||
/**
|
||||
* The Model Class
|
||||
* @var string
|
||||
*/
|
||||
protected $class = \App\Models\User::class;
|
||||
|
||||
|
||||
/**
|
||||
* Return the visible API fields.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return string[] The fields visible.
|
||||
*/
|
||||
public function fields(Model $model): array
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
if ($user === null || $user->hasPermission('admin/users') === false) {
|
||||
return ['id', 'display_name'];
|
||||
}
|
||||
|
||||
return parent::fields($model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the passed Model to an array
|
||||
*
|
||||
* @param Model $model The model to transform.
|
||||
* @return array The transformed model.
|
||||
*/
|
||||
public function transform(Model $model): array
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
$data = $model->toArray();
|
||||
$limit = $this->fields($model);
|
||||
|
||||
if (
|
||||
$user === null || (
|
||||
$user->hasPermission('admin/users') === false && strcasecmp($user->id, $model->id) !== 0
|
||||
)
|
||||
) {
|
||||
$limit = ['id', 'display_name'];
|
||||
} else {
|
||||
$data['permissions'] = $user->permissions;
|
||||
}
|
||||
|
||||
$data = arrayLimitKeys($data, $limit);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is updatable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow updating model.
|
||||
*/
|
||||
public static function updatable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
if ($user !== null) {
|
||||
return ($user->hasPermission('admin/users') === true || strcasecmp($user->id, $model->id) === 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the current model is destroyable.
|
||||
*
|
||||
* @param Model $model The model.
|
||||
* @return boolean Allow deleting model.
|
||||
*/
|
||||
public static function destroyable(Model $model): bool
|
||||
{
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
return ($user !== null && $user->hasPermission('admin/users') === true);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class CleanupTempFiles extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'app:cleanup-temp-files';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Delete temporary files that are older that 1 day';
|
||||
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$keepTime = (1 * 24 * 60 * 60); // 1 Day
|
||||
$currentTimeStamp = time();
|
||||
$deletedFileCount = 0;
|
||||
|
||||
foreach (glob(storage_path('app/tmp/*')) as $filename) {
|
||||
$fileModifiedTimeStamp = filemtime($filename);
|
||||
if (($currentTimeStamp - $fileModifiedTimeStamp) > $keepTime) {
|
||||
unlink($filename);
|
||||
$deletedFileCount++;
|
||||
}
|
||||
}
|
||||
|
||||
$this->comment('Deleted ' . $deletedFileCount . ' files');
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\MediaJob;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class RemoveStaleMediaJobs extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'app:remove-stale-media-jobs';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Remove media_jobs that have not been modified for 48 hours';
|
||||
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$threshold = now()->subHours(48);
|
||||
|
||||
$staleJobs = MediaJob::where('updated_at', '<=', $threshold)->get();
|
||||
|
||||
foreach ($staleJobs as $job) {
|
||||
$job->delete();
|
||||
}
|
||||
|
||||
$this->info(count($staleJobs) . ' stale media_jobs removed.');
|
||||
}
|
||||
}
|
||||
@@ -9,25 +9,18 @@ class Kernel extends ConsoleKernel
|
||||
{
|
||||
/**
|
||||
* Define the application's command schedule.
|
||||
*
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule The schedule.
|
||||
* @return void
|
||||
*/
|
||||
protected function schedule(Schedule $schedule): void
|
||||
{
|
||||
// $schedule->command('inspire')->hourly();
|
||||
$schedule->command('app:cleanup-temp-files')->everyThirtyMinutes();
|
||||
$schedule->command('app:remove-stale-media-jobs')->everyThirtyMinutes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the commands for the application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function commands(): void
|
||||
{
|
||||
$this->load(__DIR__ . '/Commands');
|
||||
$this->load(__DIR__.'/Commands');
|
||||
|
||||
require base_path('routes/console.php');
|
||||
}
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enum;
|
||||
|
||||
class CurlErrorCodes extends Enum
|
||||
{
|
||||
public const CURLE_UNSUPPORTED_PROTOCOL = 1;
|
||||
public const CURLE_FAILED_INIT = 2;
|
||||
public const CURLE_URL_MALFORMAT = 3;
|
||||
public const CURLE_URL_MALFORMAT_USER = 4;
|
||||
public const CURLE_COULDNT_RESOLVE_PROXY = 5;
|
||||
public const CURLE_COULDNT_RESOLVE_HOST = 6;
|
||||
public const CURLE_COULDNT_CONNECT = 7;
|
||||
public const CURLE_FTP_WEIRD_SERVER_REPLY = 8;
|
||||
public const CURLE_REMOTE_ACCESS_DENIED = 9;
|
||||
public const CURLE_FTP_WEIRD_PASS_REPLY = 11;
|
||||
public const CURLE_FTP_WEIRD_PASV_REPLY = 13;
|
||||
public const CURLE_FTP_WEIRD_227_FORMAT = 14;
|
||||
public const CURLE_FTP_CANT_GET_HOST = 15;
|
||||
public const CURLE_FTP_COULDNT_SET_TYPE = 17;
|
||||
public const CURLE_PARTIAL_FILE = 18;
|
||||
public const CURLE_FTP_COULDNT_RETR_FILE = 19;
|
||||
public const CURLE_QUOTE_ERROR = 21;
|
||||
public const CURLE_HTTP_RETURNED_ERROR = 22;
|
||||
public const CURLE_WRITE_ERROR = 23;
|
||||
public const CURLE_UPLOAD_FAILED = 25;
|
||||
public const CURLE_READ_ERROR = 26;
|
||||
public const CURLE_OUT_OF_MEMORY = 27;
|
||||
public const CURLE_OPERATION_TIMEDOUT = 28;
|
||||
public const CURLE_FTP_PORT_FAILED = 30;
|
||||
public const CURLE_FTP_COULDNT_USE_REST = 31;
|
||||
public const CURLE_RANGE_ERROR = 33;
|
||||
public const CURLE_HTTP_POST_ERROR = 34;
|
||||
public const CURLE_SSL_CONNECT_ERROR = 35;
|
||||
public const CURLE_BAD_DOWNLOAD_RESUME = 36;
|
||||
public const CURLE_FILE_COULDNT_READ_FILE = 37;
|
||||
public const CURLE_LDAP_CANNOT_BIND = 38;
|
||||
public const CURLE_LDAP_SEARCH_FAILED = 39;
|
||||
public const CURLE_FUNCTION_NOT_FOUND = 41;
|
||||
public const CURLE_ABORTED_BY_CALLBACK = 42;
|
||||
public const CURLE_BAD_FUNCTION_ARGUMENT = 43;
|
||||
public const CURLE_INTERFACE_FAILED = 45;
|
||||
public const CURLE_TOO_MANY_REDIRECTS = 47;
|
||||
public const CURLE_UNKNOWN_TELNET_OPTION = 48;
|
||||
public const CURLE_TELNET_OPTION_SYNTAX = 49;
|
||||
public const CURLE_PEER_FAILED_VERIFICATION = 51;
|
||||
public const CURLE_GOT_NOTHING = 52;
|
||||
public const CURLE_SSL_ENGINE_NOTFOUND = 53;
|
||||
public const CURLE_SSL_ENGINE_SETFAILED = 54;
|
||||
public const CURLE_SEND_ERROR = 55;
|
||||
public const CURLE_RECV_ERROR = 56;
|
||||
public const CURLE_SSL_CERTPROBLEM = 58;
|
||||
public const CURLE_SSL_CIPHER = 59;
|
||||
public const CURLE_SSL_CACERT = 60;
|
||||
public const CURLE_BAD_CONTENT_ENCODING = 61;
|
||||
public const CURLE_LDAP_INVALID_URL = 62;
|
||||
public const CURLE_FILESIZE_EXCEEDED = 63;
|
||||
public const CURLE_USE_SSL_FAILED = 64;
|
||||
public const CURLE_SEND_FAIL_REWIND = 65;
|
||||
public const CURLE_SSL_ENGINE_INITFAILED = 66;
|
||||
public const CURLE_LOGIN_DENIED = 67;
|
||||
public const CURLE_TFTP_NOTFOUND = 68;
|
||||
public const CURLE_TFTP_PERM = 69;
|
||||
public const CURLE_REMOTE_DISK_FULL = 70;
|
||||
public const CURLE_TFTP_ILLEGAL = 71;
|
||||
public const CURLE_TFTP_UNKNOWNID = 72;
|
||||
public const CURLE_REMOTE_FILE_EXISTS = 73;
|
||||
public const CURLE_TFTP_NOSUCHUSER = 74;
|
||||
public const CURLE_CONV_FAILED = 75;
|
||||
public const CURLE_CONV_REQD = 76;
|
||||
public const CURLE_SSL_CACERT_BADFILE = 77;
|
||||
public const CURLE_REMOTE_FILE_NOT_FOUND = 78;
|
||||
public const CURLE_SSH = 79;
|
||||
public const CURLE_SSL_SHUTDOWN_FAILED = 80;
|
||||
public const CURLE_AGAIN = 81;
|
||||
public const CURLE_SSL_CRL_BADFILE = 82;
|
||||
public const CURLE_SSL_ISSUER_ERROR = 83;
|
||||
public const CURLE_FTP_PRET_FAILED = 84;
|
||||
public const CURLE_RTSP_CSEQ_ERROR = 85;
|
||||
public const CURLE_RTSP_SESSION_ERROR = 86;
|
||||
public const CURLE_FTP_BAD_FILE_LIST = 87;
|
||||
public const CURLE_CHUNK_FAILED = 88;
|
||||
|
||||
|
||||
/**
|
||||
* Curl Error messages
|
||||
* @var string[]
|
||||
*/
|
||||
public static $messages = [
|
||||
1 => 'Unsupported protocol.',
|
||||
2 => 'Failed initalization.',
|
||||
3 => 'Invalid URL format.',
|
||||
4 => 'CURLE_URL_MALFORMAT_USER.',
|
||||
5 => 'Could not resolve proxy.',
|
||||
6 => 'Could not resolve host.',
|
||||
7 => 'Could not connect to host.',
|
||||
8 => 'Invalid reply from FTP server.',
|
||||
9 => 'Access denied on host.',
|
||||
11 => 'Invalid pass reply from FTP server.',
|
||||
13 => 'Invalid pasv reply from FTP server.',
|
||||
14 => 'Invalid 227 format from FTP server.',
|
||||
15 => 'Could not get FTP host.',
|
||||
17 => 'Could not set type for FTP transfer.',
|
||||
18 => 'Invalid partial size.',
|
||||
19 => 'Could not retrieve file from FTP server.',
|
||||
21 => 'Quote error.',
|
||||
22 => 'HTTP server returned error.',
|
||||
23 => 'File write error.',
|
||||
25 => 'Upload file error.',
|
||||
26 => 'File read error.',
|
||||
27 => 'Out of memory.',
|
||||
28 => 'File transfer timed out.',
|
||||
30 => 'Invalid port for FTP server.',
|
||||
31 => 'Could not use rest for FTP server.',
|
||||
33 => 'File range error.',
|
||||
34 => 'Invalid POST for HTTP server.',
|
||||
35 => 'SSL connectio error.',
|
||||
36 => 'Invalid resume download.',
|
||||
37 => 'Could not read file.',
|
||||
38 => 'Could not bind to LDAP.',
|
||||
39 => 'LDAP search failed.',
|
||||
41 => 'Function not found.',
|
||||
42 => 'Aborted by callback.',
|
||||
43 => 'Bad function argument.',
|
||||
45 => 'Interface failed.',
|
||||
47 => 'Too many redirects.',
|
||||
48 => 'Unknown telnet option.',
|
||||
49 => 'Telnet option syntax invalid.',
|
||||
51 => 'Peer failed verification.',
|
||||
52 => 'Did not receive any data.',
|
||||
53 => 'SSL engine was not found.',
|
||||
54 => 'SSL engine failed.',
|
||||
55 => 'Send data error.',
|
||||
56 => 'Receive data error.',
|
||||
58 => 'SSL certificate error.',
|
||||
59 => 'SSL cipher error.',
|
||||
60 => 'SSL CACertificate failed.',
|
||||
61 => 'Invalid content encoding.',
|
||||
62 => 'Invalid LDAP url.',
|
||||
63 => 'Filesize exceeded.',
|
||||
64 => 'SSL Failed.',
|
||||
65 => 'CURLE_SEND_FAIL_REWIND.',
|
||||
66 => 'SSL engine initalization failed.',
|
||||
67 => 'CURLE_LOGIN_DENIED.',
|
||||
68 => 'CURLE_TFTP_NOTFOUND.',
|
||||
69 => 'CURLE_TFTP_PERM.',
|
||||
70 => 'CURLE_REMOTE_DISK_FULL.',
|
||||
71 => 'CURLE_TFTP_ILLEGAL.',
|
||||
72 => 'CURLE_TFTP_UNKNOWNID.',
|
||||
73 => 'Remote file already exists.',
|
||||
74 => 'No such user on FTP server.',
|
||||
75 => 'Conversion failed.',
|
||||
76 => 'Conversion required.',
|
||||
77 => 'SSL CACertificate bad file.',
|
||||
78 => 'Remove file not found.',
|
||||
79 => 'SSH error.',
|
||||
80 => 'SSL Shutdown failed.',
|
||||
81 => 'Again.',
|
||||
82 => 'SSL bad CRL file.',
|
||||
83 => 'SSL issuer error.',
|
||||
84 => 'FTP pret failed.',
|
||||
85 => 'CURLE_RTSP_CSEQ_ERROR.',
|
||||
86 => 'CURLE_RTSP_SESSION_ERROR.',
|
||||
87 => 'CURLE_FTP_BAD_FILE_LIST.',
|
||||
88 => 'CURLE_CHUNK_FAILED.',
|
||||
|
||||
|
||||
];
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enum;
|
||||
|
||||
use ReflectionClass;
|
||||
|
||||
class Enum
|
||||
{
|
||||
/**
|
||||
* Message list
|
||||
*
|
||||
* @var array<string<static>>
|
||||
*/
|
||||
public static $messages = [];
|
||||
|
||||
/**
|
||||
* Caches reflections of enum subclasses.
|
||||
*
|
||||
* @var array<class-string<static>, ReflectionClass<static>>
|
||||
*/
|
||||
public static $reflectionCache = [];
|
||||
|
||||
|
||||
/**
|
||||
* Returns a reflection of the enum subclass.
|
||||
*
|
||||
* @return ReflectionClass<static>
|
||||
*/
|
||||
public static function getReflection(): ReflectionClass
|
||||
{
|
||||
$class = static::class;
|
||||
|
||||
return static::$reflectionCache[$class] ??= new ReflectionClass($class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the constants in the enum subclass
|
||||
*
|
||||
* @return array<static>
|
||||
*/
|
||||
public static function getConstants(): array
|
||||
{
|
||||
return static::getReflection()->getConstants();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the constants values in the enum subclass
|
||||
*
|
||||
* @return array<static>
|
||||
*/
|
||||
public static function getConstantValues(): array
|
||||
{
|
||||
return array_values(static::getReflection()->getConstants());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a message from the enum subclass
|
||||
*
|
||||
* @param integer $messageIndex The message index to retrieve.
|
||||
* @param string $defaultMessage Message to use if index does not exist.
|
||||
* @return string
|
||||
*/
|
||||
public static function getMessage(int $messageIndex, string $defaultMessage = 'Unknown'): string
|
||||
{
|
||||
if (array_key_exists($messageIndex, self::$messages) === true) {
|
||||
return self::$messages[$messageIndex];
|
||||
}
|
||||
|
||||
return $defaultMessage;
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enum;
|
||||
|
||||
class HttpResponseCodes extends Enum
|
||||
{
|
||||
public const HTTP_CONTINUE = 100;
|
||||
public const HTTP_SWITCHING_PROTOCOLS = 101;
|
||||
public const HTTP_PROCESSING = 102;
|
||||
|
||||
public const HTTP_OK = 200;
|
||||
public const HTTP_CREATED = 201;
|
||||
public const HTTP_ACCEPTED = 202;
|
||||
public const HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
|
||||
public const HTTP_NO_CONTENT = 204;
|
||||
public const HTTP_RESET_CONTENT = 205;
|
||||
public const HTTP_PARTIAL_CONTENT = 206;
|
||||
public const HTTP_MULTI_STATUS = 207;
|
||||
|
||||
public const HTTP_ALREADY_REPORTED = 208;
|
||||
|
||||
public const HTTP_IM_USED = 226;
|
||||
|
||||
public const HTTP_MULTIPLE_CHOICES = 300;
|
||||
public const HTTP_MOVED_PERMANENTLY = 301;
|
||||
public const HTTP_FOUND = 302;
|
||||
public const HTTP_SEE_OTHER = 303;
|
||||
public const HTTP_NOT_MODIFIED = 304;
|
||||
public const HTTP_USE_PROXY = 305;
|
||||
public const HTTP_RESERVED = 306;
|
||||
public const HTTP_TEMPORARY_REDIRECT = 307;
|
||||
public const HTTP_PERMANENTLY_REDIRECT = 308;
|
||||
|
||||
public const HTTP_BAD_REQUEST = 400;
|
||||
public const HTTP_UNAUTHORIZED = 401;
|
||||
public const HTTP_PAYMENT_REQUIRED = 402;
|
||||
public const HTTP_FORBIDDEN = 403;
|
||||
public const HTTP_NOT_FOUND = 404;
|
||||
public const HTTP_METHOD_NOT_ALLOWED = 405;
|
||||
public const HTTP_NOT_ACCEPTABLE = 406;
|
||||
public const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
|
||||
public const HTTP_REQUEST_TIMEOUT = 408;
|
||||
public const HTTP_CONFLICT = 409;
|
||||
public const HTTP_GONE = 410;
|
||||
public const HTTP_LENGTH_REQUIRED = 411;
|
||||
public const HTTP_PRECONDITION_FAILED = 412;
|
||||
public const HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
|
||||
public const HTTP_REQUEST_URI_TOO_LONG = 414;
|
||||
public const HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
|
||||
public const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
|
||||
public const HTTP_EXPECTATION_FAILED = 417;
|
||||
public const HTTP_I_AM_A_TEAPOT = 418;
|
||||
|
||||
public const HTTP_MISDIRECTED_REQUEST = 421;
|
||||
public const HTTP_UNPROCESSABLE_ENTITY = 422;
|
||||
public const HTTP_LOCKED = 423;
|
||||
public const HTTP_FAILED_DEPENDENCY = 424;
|
||||
public const HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL = 425;
|
||||
public const HTTP_UPGRADE_REQUIRED = 426;
|
||||
public const HTTP_PRECONDITION_REQUIRED = 428;
|
||||
public const HTTP_TOO_MANY_REQUESTS = 429;
|
||||
public const HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
|
||||
public const HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
|
||||
|
||||
public const HTTP_INTERNAL_SERVER_ERROR = 500;
|
||||
public const HTTP_NOT_IMPLEMENTED = 501;
|
||||
public const HTTP_BAD_GATEWAY = 502;
|
||||
public const HTTP_SERVICE_UNAVAILABLE = 503;
|
||||
public const HTTP_GATEWAY_TIMEOUT = 504;
|
||||
public const HTTP_VERSION_NOT_SUPPORTED = 505;
|
||||
public const HTTP_VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL = 506;
|
||||
public const HTTP_INSUFFICIENT_STORAGE = 507;
|
||||
public const HTTP_LOOP_DETECTED = 508;
|
||||
public const HTTP_NOT_EXTENDED = 510;
|
||||
public const HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511;
|
||||
|
||||
/**
|
||||
* HTTP Response Messages
|
||||
* @var string[]
|
||||
*/
|
||||
public static $statusTexts = [
|
||||
100 => 'Continue.',
|
||||
101 => 'Switching Protocols.',
|
||||
102 => 'Processing.',
|
||||
// RFC2518
|
||||
200 => 'OK.',
|
||||
201 => 'Created.',
|
||||
202 => 'Accepted.',
|
||||
203 => 'Non-Authoritative Information.',
|
||||
204 => 'No Content.',
|
||||
205 => 'Reset Content.',
|
||||
206 => 'Partial Content.',
|
||||
207 => 'Multi-Status.',
|
||||
// RFC4918
|
||||
208 => 'Already Reported.',
|
||||
// RFC5842
|
||||
226 => 'IM Used.',
|
||||
// RFC3229
|
||||
300 => 'Multiple Choices.',
|
||||
301 => 'Moved Permanently.',
|
||||
302 => 'Found.',
|
||||
303 => 'See Other.',
|
||||
304 => 'Not Modified.',
|
||||
305 => 'Use Proxy.',
|
||||
307 => 'Temporary Redirect.',
|
||||
308 => 'Permanent Redirect.',
|
||||
// RFC7238
|
||||
400 => 'Bad Request.',
|
||||
401 => 'Unauthorized.',
|
||||
402 => 'Payment Required.',
|
||||
403 => 'Forbidden.',
|
||||
404 => 'Not Found.',
|
||||
405 => 'Method Not Allowed.',
|
||||
406 => 'Not Acceptable.',
|
||||
407 => 'Proxy Authentication Required.',
|
||||
408 => 'Request Timeout.',
|
||||
409 => 'Conflict.',
|
||||
410 => 'Gone.',
|
||||
411 => 'Length Required.',
|
||||
412 => 'Precondition Failed.',
|
||||
413 => 'Payload Too Large.',
|
||||
414 => 'URI Too Long.',
|
||||
415 => 'Unsupported Media Type.',
|
||||
416 => 'Range Not Satisfiable.',
|
||||
417 => 'Expectation Failed.',
|
||||
418 => 'I\'m a teapot.',
|
||||
// RFC2324
|
||||
421 => 'Misdirected Request.',
|
||||
// RFC7540
|
||||
422 => 'Unprocessable Entity.',
|
||||
// RFC4918
|
||||
423 => 'Locked.',
|
||||
// RFC4918
|
||||
424 => 'Failed Dependency.',
|
||||
// RFC4918
|
||||
425 => 'Reserved for WebDAV advanced collections expired proposal.',
|
||||
// RFC2817
|
||||
426 => 'Upgrade Required.',
|
||||
// RFC2817
|
||||
428 => 'Precondition Required.',
|
||||
// RFC6585
|
||||
429 => 'Too Many Requests.',
|
||||
// RFC6585
|
||||
431 => 'Request Header Fields Too Large.',
|
||||
// RFC6585
|
||||
451 => 'Unavailable For Legal Reasons.',
|
||||
// RFC7725
|
||||
500 => 'Internal Server Error.',
|
||||
501 => 'Not Implemented.',
|
||||
502 => 'Bad Gateway.',
|
||||
503 => 'Service Unavailable.',
|
||||
504 => 'Gateway Timeout.',
|
||||
505 => 'HTTP Version Not Supported.',
|
||||
506 => 'Variant Also Negotiates.',
|
||||
// RFC2295
|
||||
507 => 'Insufficient Storage.',
|
||||
// RFC4918
|
||||
508 => 'Loop Detected.',
|
||||
// RFC5842
|
||||
510 => 'Not Extended.',
|
||||
// RFC2774
|
||||
511 => 'Network Authentication Required.',
|
||||
// RFC6585
|
||||
];
|
||||
}
|
||||
@@ -3,19 +3,12 @@
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Throwable;
|
||||
use PDOException;
|
||||
use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Symfony\Component\ErrorHandler\Exception\FlattenException;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
/**
|
||||
* A list of the inputs that are never flashed to the session on validation exceptions.
|
||||
* The list of the inputs that are never flashed to the session on validation exceptions.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
@@ -25,74 +18,13 @@ class Handler extends ExceptionHandler
|
||||
'password_confirmation',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Register the exception handling callbacks for the application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
// $this->renderable(function (HttpException $e, $request) {
|
||||
// if ($request->is('api/*')) {
|
||||
// $message = $e->getMessage();
|
||||
// if ($message === '') {
|
||||
// $message = HttpResponseCodes::$statusTexts[$e->getStatusCode()];
|
||||
// }
|
||||
|
||||
// return response()->json([
|
||||
// 'message' => $message
|
||||
// ], $e->getStatusCode());
|
||||
// }
|
||||
// });
|
||||
|
||||
$this->renderable(function (NotFoundHttpException $e, $request) {
|
||||
if ($request->is('api/*') === true) {
|
||||
return response()->json([
|
||||
'message' => 'Resource not found'
|
||||
], 404);
|
||||
}
|
||||
});
|
||||
|
||||
$this->renderable(function (PDOException $e, $request) {
|
||||
if ($request->is('api/*') === true) {
|
||||
return response()->json([
|
||||
'message' => 'The server is currently unavailable'
|
||||
], 503);
|
||||
}
|
||||
});
|
||||
|
||||
$this->reportable(function (Throwable $e) {
|
||||
if ($this->shouldReport($e) === true) {
|
||||
if (App::runningUnitTests() === false) {
|
||||
$this->sendEmail($e);
|
||||
}
|
||||
}
|
||||
//
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send email
|
||||
*
|
||||
* @param Throwable $exception Throwable object.
|
||||
* @return void
|
||||
*/
|
||||
public function sendEmail(Throwable $exception)
|
||||
{
|
||||
try {
|
||||
$e = FlattenException::createFromThrowable($exception);
|
||||
$handler = new HtmlErrorRenderer(true);
|
||||
$css = $handler->getStylesheet();
|
||||
$content = $handler->getBody($e);
|
||||
|
||||
Mail::send('emails.exception', compact('css', 'content'), function ($message) {
|
||||
$message
|
||||
->to('webmaster@stemmechanics.com.au')
|
||||
->subject('Exception Generated')
|
||||
;
|
||||
});
|
||||
} catch (Throwable $ex) {
|
||||
Log::error($ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filters;
|
||||
|
||||
use App\Models\Subscriber;
|
||||
|
||||
class SubscriptionFilter extends FilterAbstract
|
||||
{
|
||||
/**
|
||||
* The model class to filter
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $class = \App\Models\Subscription::class;
|
||||
|
||||
|
||||
/**
|
||||
* Return an array of attributes visible in the results
|
||||
*
|
||||
* @param array $attributes Attributes currently visible.
|
||||
* @param User|null $user Current logged in user or null.
|
||||
* @return mixed
|
||||
*/
|
||||
protected function seeAttributes(array $attributes, mixed $user)
|
||||
{
|
||||
if ($user?->hasPermission('admin/users') !== true) {
|
||||
return ['id', 'email', 'confirmed_at'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* Array Helper Functions */
|
||||
|
||||
|
||||
/**
|
||||
* Remove an item from an array.
|
||||
*
|
||||
* @param array $arr The array to check.
|
||||
* @param string|array $item The item or items to remove.
|
||||
* @return array The filtered array.
|
||||
*/
|
||||
function arrayRemoveItem(array $arr, string|array $item): array
|
||||
{
|
||||
$filteredArr = $arr;
|
||||
|
||||
if (is_string($item) === true) {
|
||||
$item = [$item];
|
||||
}
|
||||
|
||||
foreach ($item as $str) {
|
||||
$filteredArr = array_filter($arr, function ($item) use ($str) {
|
||||
return $item !== $str;
|
||||
});
|
||||
}
|
||||
|
||||
return $filteredArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array with specified the keys
|
||||
*
|
||||
* @param array $arr The array to filter.
|
||||
* @param string|array $keys The keys to keep.
|
||||
* @return array The filtered array.
|
||||
*/
|
||||
function arrayLimitKeys(array $arr, array $keys): array
|
||||
{
|
||||
return array_intersect_key($arr, array_flip($keys));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array value or default value if it does not exist
|
||||
*
|
||||
* @param string $key The key value to return if exists.
|
||||
* @param array $arr The array to check.
|
||||
* @param mixed $value The value to return if key does not exist.
|
||||
* @return mixed
|
||||
*/
|
||||
function arrayDefaultValue(string $key, array $arr, mixed $value): mixed
|
||||
{
|
||||
if (array_key_exists($key, $arr) === true) {
|
||||
return $arr[$key];
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if an item exists in an array, case insensitive
|
||||
*
|
||||
* @param string $val The value to check.
|
||||
* @param array $arr The array to check.
|
||||
* @return boolean
|
||||
*/
|
||||
function existsInArray(string $val, array $arr): bool
|
||||
{
|
||||
$exists = false;
|
||||
|
||||
foreach ($arr as $el) {
|
||||
if (strcasecmp($val, $el) === 0) {
|
||||
$exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $exists;
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* Temp File Helper Functions */
|
||||
|
||||
|
||||
/**
|
||||
* Generate a temporary file path.
|
||||
*
|
||||
* @param string $extension The file extension to use.
|
||||
* @param string $part The file part number.
|
||||
* @return string The filtered array.
|
||||
*/
|
||||
function generateTempFilePath(string $extension = '', string $part = ''): string
|
||||
{
|
||||
$temporaryDir = storage_path('app/tmp');
|
||||
if (is_dir($temporaryDir) === false) {
|
||||
mkdir($temporaryDir, 0777, true);
|
||||
}
|
||||
|
||||
return $temporaryDir . DIRECTORY_SEPARATOR . uniqid('upload_', true) . ($extension !== '' ? ".{$extension}" : '') .
|
||||
($part !== '' ? ".part-{$part}" : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Temp file information
|
||||
*
|
||||
* @param string $filePath The temp file name.
|
||||
* @return array The temp file name details.
|
||||
*/
|
||||
function tempFileInfo(string $filePath): array
|
||||
{
|
||||
$part = '';
|
||||
|
||||
// Extract the part if it's present
|
||||
if (preg_match('/\.part-(\d+)$/', $filePath, $matches) !== false) {
|
||||
$part = $matches[1];
|
||||
$filePath = substr($filePath, 0, -strlen($matches[0]));
|
||||
}
|
||||
|
||||
$info = pathinfo($filePath);
|
||||
|
||||
$directory = $info['dirname'];
|
||||
$name = $info['filename'];
|
||||
$extension = '';
|
||||
|
||||
// If there's an extension, separate it
|
||||
if (isset($info['extension']) === true) {
|
||||
$extension = $info['extension'];
|
||||
}
|
||||
|
||||
return [
|
||||
'dirname' => $directory,
|
||||
'basename' => $name . ($extension !== '' ? ".{$extension}" : ''),
|
||||
'filename' => $name,
|
||||
'extension' => $extension,
|
||||
'part' => $part,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a temporary file exists.
|
||||
*
|
||||
* @param string $dir The file parent directory.
|
||||
* @param string $name The file name.
|
||||
* @param string $extension The file extension to use.
|
||||
* @param string $part The file part number.
|
||||
* @return boolean If the file exists.
|
||||
*/
|
||||
function tempFileExists(string $dir, string $name, string $extension = '', string $part = ''): bool
|
||||
{
|
||||
$filename = constructTempFileName($dir, $name, $extension, $part);
|
||||
$exists = file_exists($filename);
|
||||
|
||||
return $exists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the temp file name based on the information
|
||||
*
|
||||
* @param string $dir The file parent directory.
|
||||
* @param string $name The file name.
|
||||
* @param string $extension The file extension to use.
|
||||
* @param string $part The file part number.
|
||||
* @return string The file path.
|
||||
*/
|
||||
function constructTempFileName(string $dir, string $name, string $extension = '', string $part = ''): string
|
||||
{
|
||||
$filename = $dir . DIRECTORY_SEPARATOR . $name . ($extension !== '' ? ".{$extension}" : '') .
|
||||
($part !== "" ? ".part-{$part}" : '');
|
||||
|
||||
return $filename;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* Type Value Helper Functions */
|
||||
|
||||
|
||||
/**
|
||||
* Is value true
|
||||
*
|
||||
* @param mixed $value Value to check.
|
||||
* @return boolean
|
||||
*/
|
||||
function isTrue(mixed $value): bool
|
||||
{
|
||||
if (is_bool($value) === true && $value === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_numeric($value) === true && intval($value) === 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_string($value) === true && in_array(strtolower($value), ['true', '1'], true) === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Conductors\AnalyticsConductor;
|
||||
use App\Enum\HttpResponseCodes;
|
||||
use App\Http\Requests\AnalyticsRequest;
|
||||
use App\Models\AnalyticsItemRequest;
|
||||
use App\Models\AnalyticsSession;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AnalyticsController extends ApiController
|
||||
{
|
||||
/**
|
||||
* AnalyticsController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth:sanctum')
|
||||
->only([
|
||||
'index',
|
||||
'update',
|
||||
'delete'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
if ($request->user() !== null && $request->user()?->hasPermission('admin/analytics') === true) {
|
||||
$request->rename([
|
||||
'type' => 'requests.type',
|
||||
'path' => 'requests.path'
|
||||
]);
|
||||
|
||||
list($collection, $total) = AnalyticsConductor::request($request);
|
||||
|
||||
return $this->respondAsResource(
|
||||
$collection,
|
||||
['resourceName' => 'session',
|
||||
'isCollection' => true,
|
||||
'appendData' => ['total' => $total]
|
||||
]
|
||||
);
|
||||
}//end if
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @param \App\Models\AnalyticsSession $session The analytics session.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Request $request, AnalyticsSession $session)
|
||||
{
|
||||
if ($request->user() !== null && $request->user()?->hasPermission('admin/analytics') === true) {
|
||||
$session->load(['requests' => function ($query) {
|
||||
$query->select('session_id', 'type', 'path', 'created_at');
|
||||
}
|
||||
]);
|
||||
|
||||
foreach ($session->requests as $requestItem) {
|
||||
$requestItem->makeHidden('session_id');
|
||||
}
|
||||
|
||||
return $this->respondAsResource(
|
||||
$session,
|
||||
['resourceName' => 'session']
|
||||
);
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\AnalyticsRequest $request The user request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(AnalyticsRequest $request)
|
||||
{
|
||||
if (AnalyticsConductor::creatable() === true) {
|
||||
$analytics = null;
|
||||
$user = $request->user();
|
||||
|
||||
$data = [
|
||||
'type' => $request->input('type'),
|
||||
'path' => $request->input('path', ''),
|
||||
'useragent' => $request->userAgent(),
|
||||
'ip' => $request->ip()
|
||||
];
|
||||
|
||||
if (
|
||||
$user !== null &&
|
||||
$user->hasPermission('admin/analytics') === true &&
|
||||
$request->has('session') === true
|
||||
) {
|
||||
$data['session_id'] = $request->input('session_id');
|
||||
$analytics = AnalyticsItemRequest::create($data);
|
||||
} else {
|
||||
$analytics = AnalyticsItemRequest::create($data);
|
||||
}
|
||||
|
||||
return $this->respondAsResource(
|
||||
AnalyticsConductor::model($request, $analytics),
|
||||
['respondCode' => HttpResponseCodes::HTTP_CREATED]
|
||||
);
|
||||
} else {
|
||||
return $this->respondForbidden();
|
||||
}//end if
|
||||
}
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use App\Enum\HttpResponseCodes;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ApiController extends Controller
|
||||
{
|
||||
/**
|
||||
* Resource name
|
||||
* @var string
|
||||
*/
|
||||
protected $resourceName = '';
|
||||
|
||||
|
||||
/**
|
||||
* Return generic json response with the given data.
|
||||
*
|
||||
* @param array $data Response data.
|
||||
* @param integer $respondCode Response status code.
|
||||
* @param array $headers Response headers.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function respondJson(
|
||||
array $data,
|
||||
int $respondCode = HttpResponseCodes::HTTP_OK,
|
||||
array $headers = []
|
||||
): JsonResponse {
|
||||
return response()->json($data, $respondCode, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return forbidden message
|
||||
*
|
||||
* @param string $message Response message.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function respondForbidden(
|
||||
string $message = 'You do not have permission to access the resource.'
|
||||
): JsonResponse {
|
||||
return response()->json(['message' => $message], HttpResponseCodes::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return forbidden message
|
||||
*
|
||||
* @param string $message Response message.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function respondNotFound(string $message = 'The resource was not found.'): JsonResponse
|
||||
{
|
||||
return response()->json(['message' => $message], HttpResponseCodes::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return too large message
|
||||
*
|
||||
* @param string $message Response message.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function respondTooLarge(string $message = 'The request entity is too large.'): JsonResponse
|
||||
{
|
||||
return response()->json(['message' => $message], HttpResponseCodes::HTTP_REQUEST_ENTITY_TOO_LARGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return no content.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function respondNoContent(): JsonResponse
|
||||
{
|
||||
return response()->json([], HttpResponseCodes::HTTP_NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return no content
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function respondNotImplemented(): JsonResponse
|
||||
{
|
||||
return response()->json([], HttpResponseCodes::HTTP_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return created.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function respondCreated(): JsonResponse
|
||||
{
|
||||
return response()->json([], HttpResponseCodes::HTTP_CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return accepted.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function respondAccepted(): JsonResponse
|
||||
{
|
||||
return response()->json([], HttpResponseCodes::HTTP_ACCEPTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return server error.
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function respondServerError(): JsonResponse
|
||||
{
|
||||
return response()->json([], HttpResponseCodes::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return single error message
|
||||
*
|
||||
* @param string $message Error message.
|
||||
* @param integer $responseCode Resource code.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function respondError(
|
||||
string $message,
|
||||
int $responseCode = HttpResponseCodes::HTTP_UNPROCESSABLE_ENTITY
|
||||
): JsonResponse {
|
||||
return response()->json([
|
||||
'message' => $message
|
||||
], $responseCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return formatted errors
|
||||
*
|
||||
* @param array $errors Error messages.
|
||||
* @param integer $responseCode Resource code.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function respondWithErrors(
|
||||
array $errors,
|
||||
int $responseCode = HttpResponseCodes::HTTP_UNPROCESSABLE_ENTITY
|
||||
): JsonResponse {
|
||||
$keys = array_keys($errors);
|
||||
$error = $errors[$keys[0]];
|
||||
|
||||
if (count($keys) > 1) {
|
||||
$additional_errors = (count($keys) - 1);
|
||||
$error .= sprintf(' (and %d more %s', $additional_errors, Str::plural('error', $additional_errors));
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => $error,
|
||||
'errors' => $errors
|
||||
], $responseCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return resource data
|
||||
*
|
||||
* @param array|Model|Collection $data Resource data.
|
||||
* @param array $options Respond options.
|
||||
* @param callable|null $validationFn Optional validation function to check the data before responding.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
protected function respondAsResource(
|
||||
mixed $data,
|
||||
array $options = [],
|
||||
$validationFn = null
|
||||
): JsonResponse {
|
||||
$isCollection = ($options['isCollection'] ?? false);
|
||||
$appendData = ($options['appendData'] ?? null);
|
||||
$resourceName = ($options['resourceName'] ?? '');
|
||||
$transformResourceName = ($options['transformResourceName'] ?? true);
|
||||
$respondCode = ($options['respondCode'] ?? HttpResponseCodes::HTTP_OK);
|
||||
|
||||
if ($data === null || ($data instanceof Collection && $data->count() === 0)) {
|
||||
$validationData = [];
|
||||
if (array_key_exists('appendData', $options) === true) {
|
||||
$validationData = $options['appendData'];
|
||||
}
|
||||
|
||||
if ($validationFn === null || $validationFn($validationData) === true) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($resourceName) === true) {
|
||||
$resourceName = $this->resourceName;
|
||||
}
|
||||
|
||||
if (empty($resourceName) === true) {
|
||||
$resourceName = get_class($this);
|
||||
$resourceName = substr($resourceName, (strrpos($resourceName, '\\') + 1));
|
||||
$resourceName = substr($resourceName, 0, strpos($resourceName, 'Controller'));
|
||||
$resourceName = strtolower($resourceName);
|
||||
}
|
||||
|
||||
$dataArray = [];
|
||||
if ($data instanceof Collection) {
|
||||
$dataArray = $data->toArray();
|
||||
} elseif (is_array($data) === true) {
|
||||
$dataArray = $data;
|
||||
} elseif ($data instanceof Model) {
|
||||
$dataArray = $data->toArray();
|
||||
}
|
||||
|
||||
$resource = [];
|
||||
if ($isCollection === true) {
|
||||
$resource = [$transformResourceName === true ? Str::plural($resourceName) : $resourceName => $dataArray];
|
||||
} else {
|
||||
$resource = [$transformResourceName === true ? Str::singular($resourceName) : $resourceName => $dataArray];
|
||||
}
|
||||
|
||||
if ($appendData !== null) {
|
||||
$resource += $appendData;
|
||||
}
|
||||
|
||||
return response()->json($resource, $respondCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Controller Model Class name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getModelClass(): string
|
||||
{
|
||||
$controllerClass = static::class;
|
||||
|
||||
$modelName = 'App\\Models\\' . Str::replaceLast('Controller', '', Str::afterLast($controllerClass, '\\'));
|
||||
|
||||
if (class_exists($modelName) === false) {
|
||||
return $modelName;
|
||||
}
|
||||
|
||||
return $modelName;
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Conductors\MediaConductor;
|
||||
use App\Conductors\ArticleConductor;
|
||||
use App\Enum\HttpResponseCodes;
|
||||
use App\Http\Requests\ArticleRequest;
|
||||
use App\Models\Media;
|
||||
use App\Models\Article;
|
||||
use App\Traits\HasAttachments;
|
||||
use App\Traits\HasGallery;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ArticleController extends ApiController
|
||||
{
|
||||
use HasAttachments;
|
||||
use HasGallery;
|
||||
|
||||
|
||||
/**
|
||||
* ApplicationController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth:sanctum')
|
||||
->only([
|
||||
'store',
|
||||
'update',
|
||||
'delete'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
list($collection, $total) = ArticleConductor::request($request);
|
||||
|
||||
return $this->respondAsResource(
|
||||
$collection,
|
||||
['isCollection' => true,
|
||||
'appendData' => ['total' => $total]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @param \App\Models\Article $article The article model.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Request $request, Article $article)
|
||||
{
|
||||
if (ArticleConductor::viewable($article) === true) {
|
||||
return $this->respondAsResource(ArticleConductor::model($request, $article));
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\ArticleRequest $request The user request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(ArticleRequest $request)
|
||||
{
|
||||
if (ArticleConductor::creatable() === true) {
|
||||
$article = Article::create($request->except(['attachments', 'gallery']));
|
||||
|
||||
if ($request->has('attachments') === true) {
|
||||
$article->addAttachments($request->get('attachments'));
|
||||
}
|
||||
|
||||
if ($request->has('gallery') === true) {
|
||||
$article->galleryAddMany($request->get('gallery'));
|
||||
}
|
||||
|
||||
return $this->respondAsResource(
|
||||
ArticleConductor::model($request, $article),
|
||||
['respondCode' => HttpResponseCodes::HTTP_CREATED]
|
||||
);
|
||||
} else {
|
||||
return $this->respondForbidden();
|
||||
}//end if
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\ArticleRequest $request The article update request.
|
||||
* @param \App\Models\Article $article The specified article.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(ArticleRequest $request, Article $article)
|
||||
{
|
||||
if (ArticleConductor::updatable($article) === true) {
|
||||
if ($request->has('attachments') === true) {
|
||||
$article->deleteAttachments();
|
||||
$article->addAttachments($request->get('attachments'));
|
||||
}
|
||||
|
||||
if ($request->has('gallery') === true) {
|
||||
$article->gallery()->delete();
|
||||
$article->galleryAddMany($request->get('gallery'));
|
||||
}
|
||||
|
||||
$article->update($request->except(['attachments', 'gallery']));
|
||||
return $this->respondAsResource(ArticleConductor::model($request, $article));
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Article $article The specified article.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Article $article)
|
||||
{
|
||||
if (ArticleConductor::destroyable($article) === true) {
|
||||
$article->delete();
|
||||
return $this->respondNoContent();
|
||||
} else {
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Enum\HttpResponseCodes;
|
||||
use App\Http\Requests\AuthLoginRequest;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
class AuthController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Resource name
|
||||
* @var string
|
||||
*/
|
||||
protected $resourceName = 'user';
|
||||
|
||||
|
||||
/**
|
||||
* ApplicationController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// $this->middleware('auth:sanctum')
|
||||
// ->only(['me']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current User details
|
||||
*
|
||||
* @param Request $request Current request data.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function me(Request $request): JsonResponse
|
||||
{
|
||||
$user = $request->user()->makeVisible(['permissions']);
|
||||
return $this->respondAsResource($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Login user with supplied creditials
|
||||
*
|
||||
* @param App\Http\Controllers\Api\AuthLoginRequest $request Created request data.
|
||||
* @return JsonResponse|void
|
||||
*/
|
||||
public function login(AuthLoginRequest $request)
|
||||
{
|
||||
$user = User::where('email', '=', $request->input('email'))->first();
|
||||
|
||||
if (
|
||||
$user !== null &&
|
||||
strlen($user->password) > 0 &&
|
||||
Hash::check($request->input('password'), $user->password) === true
|
||||
) {
|
||||
if ($user->email_verified_at === null) {
|
||||
return $this->respondWithErrors([
|
||||
'email' => 'Email address has not been verified.'
|
||||
]);
|
||||
}
|
||||
|
||||
if ($user->disabled === true) {
|
||||
return $this->respondWithErrors([
|
||||
'email' => 'Account has been disabled.'
|
||||
]);
|
||||
}
|
||||
|
||||
$token = $user->createToken('user_token')->plainTextToken;
|
||||
|
||||
$user->logins()->create([
|
||||
'token' => $token,
|
||||
'login' => now(),
|
||||
'ip_address' => $request->ip(),
|
||||
'user_agent' => $request->userAgent()
|
||||
]);
|
||||
|
||||
return $this->respondAsResource(
|
||||
$user->makeVisible(['permissions']),
|
||||
['appendData' => ['token' => $token]]
|
||||
);
|
||||
}//end if
|
||||
|
||||
return $this->respondWithErrors([
|
||||
'email' => 'Invalid email or password',
|
||||
'password' => 'Invalid email or password',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout current user
|
||||
*
|
||||
* @param Request $request Current request data.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function logout(Request $request): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
$user->logins()->where('token', $user->currentAccessToken())->update(['logout' => now()]);
|
||||
$user->currentAccessToken()->delete();
|
||||
|
||||
return $this->respondNoContent();
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Requests\ContactSendRequest;
|
||||
use App\Jobs\SendEmailJob;
|
||||
use App\Mail\Contact;
|
||||
|
||||
class ContactController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Send the request to the site admin by email
|
||||
*
|
||||
* @param \App\Http\Requests\User\ContactSendRequest $request Request data.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function send(ContactSendRequest $request)
|
||||
{
|
||||
dispatch((new SendEmailJob(
|
||||
config('contact.contact_address'),
|
||||
new Contact(
|
||||
$request->input('name'),
|
||||
$request->input('email'),
|
||||
$request->input('content')
|
||||
)
|
||||
)))->onQueue('mail');
|
||||
|
||||
return $this->respondCreated();
|
||||
}
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Enum\HttpResponseCodes;
|
||||
use App\Models\Event;
|
||||
use App\Conductors\EventConductor;
|
||||
use App\Conductors\MediaConductor;
|
||||
use App\Conductors\UserConductor;
|
||||
use App\Http\Requests\EventRequest;
|
||||
use App\Models\Media;
|
||||
use App\Models\User;
|
||||
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class EventController extends ApiController
|
||||
{
|
||||
/**
|
||||
* ApplicationController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth:sanctum')
|
||||
->only(['store','update','destroy', 'userAdd', 'userUpdate', 'userDelete']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
list($collection, $total) = EventConductor::request($request);
|
||||
|
||||
return $this->respondAsResource(
|
||||
$collection,
|
||||
['isCollection' => true,
|
||||
'appendData' => ['total' => $total]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @param \App\Models\Event $event The specified event.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Request $request, Event $event)
|
||||
{
|
||||
if (EventConductor::viewable($event) === true) {
|
||||
return $this->respondAsResource(EventConductor::model($request, $event));
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\EventRequest $request The request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(EventRequest $request)
|
||||
{
|
||||
if (EventConductor::creatable() === true) {
|
||||
$event = Event::create($request->except(['attachments']));
|
||||
|
||||
if ($request->has('attachments') === true) {
|
||||
$event->addAttachments($request->get('attachments'));
|
||||
}
|
||||
|
||||
return $this->respondAsResource(
|
||||
EventConductor::model($request, $event),
|
||||
['respondCode' => HttpResponseCodes::HTTP_CREATED]
|
||||
);
|
||||
} else {
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\EventRequest $request The endpoint request.
|
||||
* @param \App\Models\Event $event The specified event.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(EventRequest $request, Event $event)
|
||||
{
|
||||
if (EventConductor::updatable($event) === true) {
|
||||
if ($request->has('attachments') === true) {
|
||||
$event->deleteAttachments();
|
||||
$event->addAttachments($request->get('attachments'));
|
||||
}
|
||||
|
||||
$event->update($request->except(['attachments']));
|
||||
return $this->respondAsResource(EventConductor::model($request, $event));
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Event $event The specified event.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Event $event)
|
||||
{
|
||||
if (EventConductor::destroyable($event) === true) {
|
||||
$event->delete();
|
||||
return $this->respondNoContent();
|
||||
} else {
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List users of Event
|
||||
* @param Request $request The HTTP request.
|
||||
* @param Event $event Event model.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function userList(Request $request, Event $event): JsonResponse
|
||||
{
|
||||
$authUser = $request->user();
|
||||
$eventUsers = $event->users;
|
||||
|
||||
if ($authUser !== null) {
|
||||
$isAdmin = $authUser->hasPermission('admin/events');
|
||||
$isEventUser = $eventUsers->contains($authUser->id);
|
||||
|
||||
if ($isAdmin === true || $isEventUser === true) {
|
||||
if ($isAdmin === false) {
|
||||
$eventUsers = $eventUsers->filter(function ($user) use ($authUser) {
|
||||
return $user->id === $authUser->id;
|
||||
});
|
||||
}
|
||||
|
||||
return $this->respondAsResource(
|
||||
UserConductor::collection($request, $eventUsers),
|
||||
[
|
||||
'isCollection' => true,
|
||||
'resourceName' => 'users'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return $this->respondNotFound();
|
||||
}//end if
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add user to Event
|
||||
* @param Request $request The HTTP request.
|
||||
* @param Event $event Event model.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function userAdd(Request $request, Event $event): JsonResponse
|
||||
{
|
||||
$authUser = $request->user();
|
||||
if ($authUser !== null && $authUser->hasPermission('admin/events') === true) {
|
||||
if ($request->has("users") === true) {
|
||||
$eventUsers = $event->users()->pluck('user_id')->toArray(); // Get the current users in the event
|
||||
$requestedUsers = $request->input("users"); // Get the requested users
|
||||
|
||||
$usersToAdd = array_diff($requestedUsers, $eventUsers); // Users to add
|
||||
$usersToRemove = array_diff($eventUsers, $requestedUsers); // Users to remove
|
||||
|
||||
// Add missing users
|
||||
foreach ($usersToAdd as $userToAdd) {
|
||||
if (User::find($userToAdd) !== null) {
|
||||
$event->users()->attach($userToAdd);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove extra users
|
||||
foreach ($usersToRemove as $userToRemove) {
|
||||
$event->users()->detach($userToRemove);
|
||||
}
|
||||
|
||||
return $this->respondNoContent();
|
||||
}//end if
|
||||
|
||||
return $this->respondWithErrors(['users' => 'The user list was not found']);
|
||||
}//end if
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user
|
||||
* @param Request $request The HTTP request.
|
||||
* @param Event $event Event model.
|
||||
* @return void
|
||||
*/
|
||||
public function userUpdate(Request $request, Event $event): void
|
||||
{
|
||||
// only admin/events permitted
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user from event
|
||||
*
|
||||
* @param Request $request The HTTP request.
|
||||
* @param Event $event Event model.
|
||||
* @param User $user User model.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function userDelete(Request $request, Event $event, User $user): JsonResponse
|
||||
{
|
||||
$authUser = $request->user();
|
||||
if ($authUser !== null && $authUser->hasPermission('admin/events') === true) {
|
||||
$eventUsers = $event->users;
|
||||
if ($eventUsers->find($user->id) !== null) {
|
||||
$eventUsers->detach($user->id);
|
||||
return $this->respondNoContent();
|
||||
} else {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Enum\HttpResponseCodes;
|
||||
use App\Models\Media;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class InfoController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$info = [
|
||||
"version" => "1.0.0",
|
||||
"max_upload_size" => Media::getMaxUploadSize()
|
||||
];
|
||||
|
||||
return $this->respondJson($info);
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class LogController extends ApiController
|
||||
{
|
||||
/**
|
||||
* ApplicationController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth:sanctum')
|
||||
->only(['show']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param Request $request The log request.
|
||||
* @param string $name The log name.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Request $request, string $name)
|
||||
{
|
||||
if ($request->user()?->hasPermission('logs/' . $name) === true) {
|
||||
switch (strtolower($name)) {
|
||||
case 'discord':
|
||||
$data = [];
|
||||
|
||||
$log = $request->get('log');
|
||||
if ($log === null) {
|
||||
$log = ['output', 'error'];
|
||||
} else {
|
||||
$log = explode(',', strtolower($log));
|
||||
}
|
||||
|
||||
$lines = intval($request->get('lines', 50));
|
||||
if ($lines > 100) {
|
||||
$lines = 100;
|
||||
} elseif ($lines < 0) {
|
||||
$lines = 1;
|
||||
}
|
||||
|
||||
$before = $request->get('before');
|
||||
if ($before !== null) {
|
||||
$before = preg_split(
|
||||
"/([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/",
|
||||
$before,
|
||||
-1,
|
||||
(PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY)
|
||||
);
|
||||
if (count($before) !== 6) {
|
||||
$before = null;
|
||||
}
|
||||
}
|
||||
|
||||
$after = $request->get('after');
|
||||
if ($after !== null) {
|
||||
$after = preg_split(
|
||||
"/([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/",
|
||||
$after,
|
||||
-1,
|
||||
(PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY)
|
||||
);
|
||||
if (count($after) !== 6) {
|
||||
$after = null;
|
||||
}
|
||||
}
|
||||
|
||||
$logFiles = [
|
||||
[
|
||||
'name' => 'output',
|
||||
'path' => '/home/discordbot/.pm2/logs/stemmech-discordbot-out-0.log'
|
||||
],[
|
||||
'name' => 'error',
|
||||
'path' => '/home/discordbot/.pm2/logs/stemmech-discordbot-error-0.log'
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($logFiles as $logFile) {
|
||||
if (in_array($logFile['name'], $log) === true) {
|
||||
$logContent = '';
|
||||
|
||||
if (file_exists($logFile['path']) === true) {
|
||||
$logContent = file_get_contents($logFile['path']);
|
||||
}
|
||||
|
||||
$logArray = preg_split(
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
"/(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}: (?:(?!\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}: )[\s\S])*)/",
|
||||
$logContent,
|
||||
-1,
|
||||
(PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY)
|
||||
);
|
||||
|
||||
$logContent = '';
|
||||
$logLineCount = 0;
|
||||
$logLineSkip = false;
|
||||
foreach (array_reverse($logArray) as $logLine) {
|
||||
$lineDate = preg_split(
|
||||
"/^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2}): /",
|
||||
$logLine,
|
||||
-1,
|
||||
(PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY)
|
||||
);
|
||||
if (count($lineDate) >= 6) {
|
||||
$logLineSkip = false;
|
||||
|
||||
// Is line before
|
||||
if (
|
||||
$before !== null && (
|
||||
$lineDate[0] > $before[0] ||
|
||||
$lineDate[1] > $before[1] ||
|
||||
$lineDate[2] > $before[2] ||
|
||||
$lineDate[3] > $before[3] ||
|
||||
$lineDate[4] > $before[4] ||
|
||||
$lineDate[5] > $before[5]
|
||||
)
|
||||
) {
|
||||
$logLineSkip = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is line after
|
||||
if (
|
||||
$after !== null && (
|
||||
$after[0] > $lineDate[0] ||
|
||||
$after[1] > $lineDate[1] ||
|
||||
$after[2] > $lineDate[2] ||
|
||||
$after[3] > $lineDate[3] ||
|
||||
$after[4] > $lineDate[4] ||
|
||||
$after[5] > $lineDate[5]
|
||||
)
|
||||
) {
|
||||
$logLineSkip = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$logLineCount += 1;
|
||||
}//end if
|
||||
|
||||
if ($logLineCount > $lines) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($logLineSkip === false) {
|
||||
$logContent .= $logLine;
|
||||
}
|
||||
}//end foreach
|
||||
|
||||
$data[$logFile['name']] = $logContent;
|
||||
}//end if
|
||||
}//end foreach
|
||||
|
||||
return $this->respondJson([
|
||||
'log' => $data
|
||||
]);
|
||||
}//end switch
|
||||
}//end if
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
}
|
||||
@@ -1,443 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Conductors\MediaConductor;
|
||||
use App\Conductors\MediaJobConductor;
|
||||
use App\Enum\HttpResponseCodes;
|
||||
use App\Http\Requests\MediaRequest;
|
||||
use App\Models\Media;
|
||||
use App\Models\MediaJob;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Laravel\Sanctum\PersonalAccessToken;
|
||||
|
||||
class MediaController extends ApiController
|
||||
{
|
||||
/**
|
||||
* ApplicationController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth:sanctum')
|
||||
->only(['store','update','destroy']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
list($collection, $total) = MediaConductor::request($request);
|
||||
|
||||
return $this->respondAsResource(
|
||||
$collection,
|
||||
['isCollection' => true,
|
||||
'appendData' => ['total' => $total]
|
||||
],
|
||||
function ($options) {
|
||||
return $options['total'] === 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @param \App\Models\Media $medium The request media.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Request $request, Media $medium)
|
||||
{
|
||||
if (MediaConductor::viewable($medium) === true) {
|
||||
return $this->respondAsResource(MediaConductor::model($request, $medium));
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new media resource
|
||||
*
|
||||
* @param \App\Http\Requests\MediaRequest $request The uploaded media.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(MediaRequest $request)
|
||||
{
|
||||
// allowed to create a media item
|
||||
if (MediaConductor::creatable() === false) {
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
// check for file
|
||||
$file = $request->file('file');
|
||||
if ($file === null) {
|
||||
return $this->respondWithErrors(['file' => 'The browser did not upload the file correctly to the server.']);
|
||||
}
|
||||
|
||||
return $this->storeOrUpdate($request, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the media resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\MediaRequest $request The update request.
|
||||
* @param \App\Models\Media $medium The specified media.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(MediaRequest $request, Media $medium)
|
||||
{
|
||||
// allowed to update a media item
|
||||
if (MediaConductor::updatable($medium) === false) {
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
return $this->storeOrUpdate($request, $medium);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new media resource
|
||||
*
|
||||
* @param \App\Http\Requests\MediaRequest $request The uploaded media.
|
||||
* @param \App\Models\Media|null $medium The specified media.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function storeOrUpdate(MediaRequest $request, Media|null $medium)
|
||||
{
|
||||
$file = $request->file('file');
|
||||
if ($file !== null) {
|
||||
// validate file object
|
||||
if ($file->isValid() !== true) {
|
||||
switch ($file->getError()) {
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
case UPLOAD_ERR_FORM_SIZE:
|
||||
return $this->respondTooLarge();
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
return $this->respondWithErrors([$file => 'The file upload was interrupted.']);
|
||||
default:
|
||||
return $this->respondWithErrors(
|
||||
[$file => 'An error occurred uploading the file to the server.']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($file->getSize() > Media::getMaxUploadSize()) {
|
||||
return $this->respondTooLarge();
|
||||
}
|
||||
}
|
||||
|
||||
// create/get media job
|
||||
$mediaJob = null;
|
||||
$data = [];
|
||||
|
||||
if ($request->missing('job_id') === true) {
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
|
||||
$mediaJob = new MediaJob();
|
||||
$mediaJob->user_id = $user->id;
|
||||
if ($medium !== null) {
|
||||
$mediaJob->media_id = $medium->id;
|
||||
}
|
||||
|
||||
if ($request->has('title') === true || $file !== null) {
|
||||
$data['title'] = $request->get('title', '');
|
||||
}
|
||||
|
||||
if ($request->has('name') === true || $file !== null) {
|
||||
$data['name'] = (
|
||||
$request->has('chunk') === true ? $request->get('name', '') : $file->getClientOriginalName()
|
||||
);
|
||||
}
|
||||
|
||||
if ($file !== null) {
|
||||
$data['size'] = $request->has('chunk') === true ? intval($request->get('size', 0)) : $file->getSize();
|
||||
$data['mime_type'] = (
|
||||
$request->has('chunk') === true ? $request->get('mime_type', '') : $file->getMimeType()
|
||||
);
|
||||
}
|
||||
|
||||
if ($request->has('storage') === true || $file !== null) {
|
||||
$data['storage'] = $request->get('storage', '');
|
||||
}
|
||||
|
||||
if ($request->has('security_type') === true || $file !== null) {
|
||||
$data['security']['type'] = $request->get('security_type', '');
|
||||
$data['security']['data'] = $request->get('security_data', '');
|
||||
|
||||
if ($data['security']['type'] === '') {
|
||||
$data['security']['data'] = '';
|
||||
}
|
||||
|
||||
if ($medium === null || strcasecmp($data['security']['type'], $medium->security_type) !== 0) {
|
||||
if ($request->has('storage') === false) {
|
||||
$mime_type = $request->get('mime_type', $medium === null ? '' : $medium->mime_type);
|
||||
$data['storage'] = Media::recommendedStorage($mime_type, $data['security']['type']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
array_key_exists('storage', $data) === true && (
|
||||
array_key_exists('security', $data) === true &&
|
||||
array_key_exists('type', $data['security']) === true
|
||||
) &&
|
||||
array_key_exists('mime_type', $data) === true &&
|
||||
$data['mime_type'] !== ""
|
||||
) {
|
||||
$error = Media::verifyStorage($data['mime_type'], $data['security']['type'], $data['storage']);
|
||||
// Log::error($data['mime_type'] . ' - ' . $data['security']['type'] . ' - ' . $data['storage']);
|
||||
switch ($error) {
|
||||
case Media::STORAGE_VALID:
|
||||
break;
|
||||
case Media::STORAGE_MIME_MISSING:
|
||||
return $this->respondWithErrors(['mime_type' => 'The file type is required.']);
|
||||
case Media::STORAGE_NOT_FOUND:
|
||||
return $this->respondWithErrors(['storage' => 'Storage was not found.']);
|
||||
case Media::STORAGE_INVALID_SECURITY:
|
||||
return $this->respondWithErrors(
|
||||
['storage' => 'Storage invalid for this security requirement.']
|
||||
);
|
||||
default:
|
||||
return $this->respondWithErrors(['storage' => 'Storage verification error occurred.']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->has('transform') === true) {
|
||||
$transform = [];
|
||||
|
||||
foreach (explode(',', $request->get('transform', '')) as $value) {
|
||||
if (is_string($value) === true) {
|
||||
if (preg_match('/^rotate-(-?\d+)$/', $value, $matches) !== false) {
|
||||
$transform['rotate'] = $matches[1];
|
||||
} elseif (preg_match('/^flip-([vh]|vh|hv)$/', $value, $matches) !== false) {
|
||||
$transform['flip'] = $matches[1];
|
||||
} elseif (preg_match('/^crop-(\d+)-(\d+)$/', $value, $matches) !== false) {
|
||||
$transform['crop'] = ['width' => $matches[1], 'height' => $matches[2]];
|
||||
} elseif (preg_match('/^crop-(\d+)-(\d+)-(\d+)-(\d+)$/', $value, $matches) !== false) {
|
||||
$transform['crop'] = [
|
||||
'width' => $matches[1],
|
||||
'height' => $matches[2],
|
||||
'x' => $matches[3],
|
||||
'y' => $matches[4]
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($transform) > 0) {
|
||||
$data['transform'] = $transform;
|
||||
}
|
||||
}//end if
|
||||
|
||||
$mediaJob->setStatusWaiting();
|
||||
} else {
|
||||
$mediaJob = MediaJob::find($request->get('job_id'));
|
||||
if ($mediaJob === null || $mediaJob->exists() === false) {
|
||||
$this->respondNotFound();
|
||||
}
|
||||
|
||||
$data = json_decode($mediaJob->data, true);
|
||||
if ($data === null) {
|
||||
Log::error(`{$mediaJob->id} contains no data`);
|
||||
return $this->respondServerError();
|
||||
}
|
||||
|
||||
if (array_key_exists('name', $data) === false) {
|
||||
Log::error(`{$mediaJob->id} data does not contain the name key`);
|
||||
return $this->respondServerError();
|
||||
}
|
||||
}//end if
|
||||
|
||||
if ($mediaJob === null) {
|
||||
Log::error(`media job does not exist`);
|
||||
return $this->respondServerError();
|
||||
}
|
||||
|
||||
// save uploaded file
|
||||
if ($file !== null) {
|
||||
if ($data['name'] === '') {
|
||||
Log::error(`filename does not exist`);
|
||||
return $this->respondServerError();
|
||||
}
|
||||
|
||||
$temporaryFilePath = generateTempFilePath(
|
||||
pathinfo($data['name'], PATHINFO_EXTENSION),
|
||||
$request->get('chunk', '')
|
||||
);
|
||||
copy($file->path(), $temporaryFilePath);
|
||||
|
||||
if ($request->has('chunk') === true) {
|
||||
$data['chunks'][$request->get('chunk', '1')] = $temporaryFilePath;
|
||||
$data['chunk_count'] = $request->get('chunk_count', 1);
|
||||
} else {
|
||||
$data['file'] = $temporaryFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
$mediaJob->data = json_encode($data, true);
|
||||
$mediaJob->save();
|
||||
$mediaJob->process();
|
||||
|
||||
return $this->respondAsResource(
|
||||
MediaJobConductor::model($request, $mediaJob),
|
||||
['resourceName' => 'media_job', 'respondCode' => HttpResponseCodes::HTTP_ACCEPTED]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Media $medium Specified media file.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Media $medium)
|
||||
{
|
||||
if (MediaConductor::destroyable($medium) === true) {
|
||||
$medium->delete();
|
||||
return $this->respondNoContent();
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @param \App\Models\Media $media Specified media.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function download(Request $request, Media $media): Response
|
||||
{
|
||||
$headers = [];
|
||||
|
||||
/* Check file exists */
|
||||
if (Storage::disk($media->storage)->exists($media->name) === false) {
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
$updated_at = Carbon::parse(Storage::disk($media->storage)->lastModified($media->name));
|
||||
|
||||
$headerPragma = 'no-cache';
|
||||
$headerCacheControl = 'max-age=0, must-revalidate';
|
||||
$headerExpires = $updated_at->toRfc2822String();
|
||||
|
||||
/* construct user if can */
|
||||
$user = $request->user();
|
||||
if ($user === null && $request->has('token') === true) {
|
||||
$accessToken = PersonalAccessToken::findToken(urldecode($request->input('token')));
|
||||
|
||||
if (
|
||||
$accessToken !== null && (config('sanctum.expiration') === null ||
|
||||
$accessToken->created_at->lte(now()->subMinutes(config('sanctum.expiration'))) === false)
|
||||
) {
|
||||
$user = $accessToken->tokenable;
|
||||
}
|
||||
}
|
||||
|
||||
if ($media->security_type === '') {
|
||||
/* no security */
|
||||
$headerPragma = 'public';
|
||||
$headerExpires = $updated_at->addMonth()->toRfc2822String();
|
||||
} elseif (strcasecmp('password', $media->security_type) === 0) {
|
||||
/* password */
|
||||
if (
|
||||
($user === null || $user->hasPermission('admin/media') === false) &&
|
||||
($request->has('password') === false || $request->get('password') !== $media->security_data)
|
||||
) {
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
} elseif (strcasecmp('permission', $media->security_type) === 0) {
|
||||
/* permission */
|
||||
if (
|
||||
$user === null || (
|
||||
$user->hasPermission('admin/media') === false &&
|
||||
$user->hasPermission($media->security_data) === false
|
||||
)
|
||||
) {
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
}//end if
|
||||
|
||||
// deepcode ignore InsecureHash: Browsers expect Etag to be a md5 hash
|
||||
$headerEtag = md5($updated_at->format('U'));
|
||||
$headerLastModified = $updated_at->toRfc2822String();
|
||||
|
||||
$headers = [
|
||||
'Cache-Control' => $headerCacheControl,
|
||||
'Content-Disposition' => sprintf('inline; filename="%s"', basename($media->name)),
|
||||
'Etag' => $headerEtag,
|
||||
'Expires' => $headerExpires,
|
||||
'Last-Modified' => $headerLastModified,
|
||||
'Pragma' => $headerPragma,
|
||||
];
|
||||
|
||||
$server = request()->server;
|
||||
|
||||
$requestModifiedSince = $server->has('HTTP_IF_MODIFIED_SINCE') &&
|
||||
$server->get('HTTP_IF_MODIFIED_SINCE') === $headerLastModified;
|
||||
|
||||
$requestNoneMatch = $server->has('HTTP_IF_NONE_MATCH') &&
|
||||
$server->get('HTTP_IF_NONE_MATCH') === $headerEtag;
|
||||
|
||||
if ($requestModifiedSince === true || $requestNoneMatch === true) {
|
||||
return response()->make('', 304, $headers);
|
||||
}
|
||||
|
||||
$headers['Content-Type'] = Storage::disk($media->storage)->mimeType($media->name);
|
||||
$headers['Content-Length'] = Storage::disk($media->storage)->size($media->name);
|
||||
$headers['Content-Disposition'] = 'attachment; filename="' . basename($media->name) . '"';
|
||||
|
||||
$stream = Storage::disk($media->storage)->readStream($media->name);
|
||||
return response()->stream(
|
||||
function () use ($stream) {
|
||||
while (ob_get_level() > 0) {
|
||||
ob_end_flush();
|
||||
}
|
||||
fpassthru($stream);
|
||||
},
|
||||
200,
|
||||
$headers
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a File item in a request is valid
|
||||
*
|
||||
* @param UploadedFile $file The file to validate.
|
||||
* @param string $errorKey The error key to use.
|
||||
* @return JsonResponse|null
|
||||
*/
|
||||
private function validateFileObject(UploadedFile $file, string $errorKey = 'file'): JsonResponse|null
|
||||
{
|
||||
if ($file->isValid() !== true) {
|
||||
switch ($file->getError()) {
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
case UPLOAD_ERR_FORM_SIZE:
|
||||
return $this->respondTooLarge();
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
return $this->respondWithErrors([$errorKey => 'The file upload was interrupted.']);
|
||||
default:
|
||||
return $this->respondWithErrors(
|
||||
[$errorKey => 'An error occurred uploading the file to the server.']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($file->getSize() > Media::getMaxUploadSize()) {
|
||||
return $this->respondTooLarge();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Conductors\MediaJobConductor;
|
||||
use App\Http\Controllers\Api\ApiController;
|
||||
use App\Models\MediaJob;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class MediaJobController extends ApiController
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
list($collection, $total) = MediaJobConductor::request($request);
|
||||
|
||||
return $this->respondAsResource(
|
||||
$collection,
|
||||
['isCollection' => true,
|
||||
'appendData' => ['total' => $total],
|
||||
'resourceName' => 'media_job'
|
||||
],
|
||||
function ($options) {
|
||||
return $options['total'] === 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @param \App\Models\MediaJob $mediaJob The request media job.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Request $request, MediaJob $mediaJob)
|
||||
{
|
||||
if (MediaJobConductor::viewable($mediaJob) === true) {
|
||||
return $this->respondAsResource(
|
||||
MediaJobConductor::model($request, $mediaJob),
|
||||
['resourceName' => 'media_job']
|
||||
);
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use thiagoalessio\TesseractOCR\TesseractOCR;
|
||||
use FFMpeg;
|
||||
use App\Enum\CurlErrorCodes;
|
||||
|
||||
class OCRController extends ApiController
|
||||
{
|
||||
/**
|
||||
* ApplicationController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// $this->middleware('auth:sanctum')
|
||||
// ->only(['show']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param Request $request The log request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Request $request)
|
||||
{
|
||||
// if ($request->user()?->hasPermission('logs/' . $name) === true) {
|
||||
$url = $request->get('url');
|
||||
if ($url !== null) {
|
||||
$data = ['ocr' => []];
|
||||
|
||||
$filters = $request->get('filters', ['tesseract']);
|
||||
if (is_array($filters) === false) {
|
||||
$filters = explode(',', $filters);
|
||||
}
|
||||
|
||||
$tesseractOEM = $request->get('tesseract.oem');
|
||||
$tesseractDigits = $request->get('tesseract.digits');
|
||||
$tesseractAllowlist = $request->get('tesseract.allowlist');
|
||||
|
||||
// Download URL
|
||||
$urlDownloadFilePath = tempnam(sys_get_temp_dir(), 'download');
|
||||
$maxDownloadSize = (1024 * 1024); // 1MB
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
|
||||
// We need progress updates to break the connection mid-way
|
||||
curl_setopt($ch, CURLOPT_BUFFERSIZE, 128); // more progress info
|
||||
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
|
||||
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, function (
|
||||
$downloadSize,
|
||||
$downloaded,
|
||||
$uploadSize,
|
||||
$uploaded
|
||||
) use ($maxDownloadSize) {
|
||||
return ($downloaded > $maxDownloadSize) ? 1 : 0;
|
||||
});
|
||||
|
||||
$curlResult = curl_exec($ch);
|
||||
$curlError = curl_errno($ch);
|
||||
$curlSize = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
|
||||
curl_close($ch);
|
||||
if ($curlError !== 0) {
|
||||
$error = 'File size is larger then allowed';
|
||||
if ($curlError !== CurlErrorCodes::CURLE_ABORTED_BY_CALLBACK) {
|
||||
$error = CurlErrorCodes::getMessage($curlError);
|
||||
}
|
||||
|
||||
return $this->respondWithErrors(['url' => $error]);
|
||||
}
|
||||
|
||||
// Save url file
|
||||
file_put_contents($urlDownloadFilePath, $curlResult);
|
||||
$urlDownloadFilePathBase = preg_replace('/\\.[^.\\s]{3,4}$/', '', $urlDownloadFilePath);
|
||||
|
||||
// tesseract (overall)
|
||||
$ocr = null;
|
||||
foreach ($filters as $filterItem) {
|
||||
if (str_starts_with($filterItem, 'tesseract') === true) {
|
||||
$ocr = new TesseractOCR();
|
||||
$ocr->image($urlDownloadFilePath);
|
||||
if ($tesseractOEM !== null) {
|
||||
$ocr->oem($tesseractOEM);
|
||||
}
|
||||
if ($tesseractDigits !== null) {
|
||||
$ocr->digits();
|
||||
}
|
||||
if ($tesseractAllowlist !== null) {
|
||||
$ocr->allowlist($tesseractAllowlist);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Image Filter Function
|
||||
$tesseractImageFilterFunc = function ($filter, $options = null) use ($curlResult, $curlSize, $ocr) {
|
||||
$result = '';
|
||||
$img = imagecreatefromstring($curlResult);
|
||||
if (
|
||||
$img !== false && (($options !== null && imagefilter($img, $filter, $options) === true) ||
|
||||
($options === null && imagefilter($img, $filter) === true))
|
||||
) {
|
||||
ob_start();
|
||||
imagepng($img);
|
||||
$imgData = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$imgDataSize = strlen($imgData);
|
||||
|
||||
$ocr->imageData($imgData, $imgDataSize);
|
||||
imagedestroy($img);
|
||||
|
||||
$result = $ocr->run(500);
|
||||
}
|
||||
|
||||
return $result;
|
||||
};
|
||||
|
||||
// Image Scale Function
|
||||
$tesseractImageScaleFunc = function ($scaleFunc) use ($curlResult, $ocr) {
|
||||
$result = '';
|
||||
$srcImage = imagecreatefromstring($curlResult);
|
||||
$srcWidth = imagesx($srcImage);
|
||||
$srcHeight = imagesy($srcImage);
|
||||
|
||||
$dstWidth = $scaleFunc($srcWidth);
|
||||
$dstHeight = $scaleFunc($srcHeight);
|
||||
$dstImage = imagecreatetruecolor($dstWidth, $dstHeight);
|
||||
|
||||
imagecopyresampled($dstImage, $srcImage, 0, 0, 0, 0, $dstWidth, $dstHeight, $srcWidth, $srcHeight);
|
||||
|
||||
ob_start();
|
||||
imagepng($dstImage);
|
||||
$imgData = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$imgDataSize = strlen($imgData);
|
||||
|
||||
imagedestroy($srcImage);
|
||||
imagedestroy($dstImage);
|
||||
|
||||
$ocr->imageData($imgData, $imgDataSize);
|
||||
$result = $ocr->run(500);
|
||||
return $result;
|
||||
};
|
||||
|
||||
// filter: tesseract
|
||||
if (in_array('tesseract', $filters) === true) {
|
||||
$data['ocr']['tesseract'] = $ocr->run(500);
|
||||
}
|
||||
|
||||
// filter: tesseract.grayscale
|
||||
if (in_array('tesseract.grayscale', $filters) === true) {
|
||||
$data['ocr']['tesseract.grayscale'] = $tesseractImageFilterFunc(IMG_FILTER_GRAYSCALE);
|
||||
}
|
||||
|
||||
// filter: tesseract.double_scale
|
||||
if (in_array('tesseract.double_scale', $filters) === true) {
|
||||
$data['ocr']['tesseract.double_scale'] = $tesseractImageScaleFunc(function ($size) {
|
||||
return $size * 2;
|
||||
});
|
||||
}
|
||||
|
||||
// filter: tesseract.half_scale
|
||||
if (in_array('tesseract.half_scale', $filters) === true) {
|
||||
$data['ocr']['tesseract.half_scale'] = $tesseractImageScaleFunc(function ($size) {
|
||||
return $size / 2;
|
||||
});
|
||||
}
|
||||
|
||||
// filter: tesseract.edgedetect
|
||||
if (in_array('tesseract.edgedetect', $filters) === true) {
|
||||
$data['ocr']['tesseract.edgedetect'] = $tesseractImageFilterFunc(IMG_FILTER_EDGEDETECT);
|
||||
}
|
||||
|
||||
// filter: tesseract.mean_removal
|
||||
if (in_array('tesseract.mean_removal', $filters) === true) {
|
||||
$data['ocr']['tesseract.mean_removal'] = $tesseractImageFilterFunc(IMG_FILTER_MEAN_REMOVAL);
|
||||
}
|
||||
|
||||
// filter: tesseract.negate
|
||||
if (in_array('tesseract.negate', $filters) === true) {
|
||||
$data['ocr']['tesseract.negate'] = $tesseractImageFilterFunc(IMG_FILTER_NEGATE);
|
||||
}
|
||||
|
||||
// filter: tesseract.pixelate
|
||||
if (in_array('tesseract.pixelate', $filters) === true) {
|
||||
$data['ocr']['tesseract.pixelate'] = $tesseractImageFilterFunc(IMG_FILTER_PIXELATE, 3);
|
||||
}
|
||||
|
||||
// filter: keras
|
||||
if (in_array('keras', $filters) === true) {
|
||||
$cmd = '/usr/bin/python3 ' . base_path() . '/scripts/keras_oc.py ' . urlencode($url);
|
||||
$command = escapeshellcmd($cmd);
|
||||
$output = shell_exec($cmd);
|
||||
if ($output !== null && strlen($output) > 0) {
|
||||
$output = substr($output, (strpos($output, '----------START----------') + 25));
|
||||
} else {
|
||||
$output = '';
|
||||
}
|
||||
$data['ocr']['keras'] = $output;
|
||||
}
|
||||
|
||||
unlink($urlDownloadFilePath);
|
||||
return $this->respondJson($data);
|
||||
}//end if
|
||||
|
||||
return $this->respondWithErrors(['url' => 'url is missing']);
|
||||
}
|
||||
|
||||
// $ffmpeg = FFMpeg\FFMpeg::create();
|
||||
|
||||
// // Load the input video
|
||||
// $inputFile = $ffmpeg->open('input.mp4');
|
||||
|
||||
// // Split the video into individual frames
|
||||
// $videoFrames = $inputFile->frames();
|
||||
// foreach ($videoFrames as $frame) {
|
||||
// // Save the frame as a PNG
|
||||
// $frame->save(new FFMpeg\Format\Video\PNG(), 'frame-' . $frame->getMetadata('pts') . '.png');
|
||||
|
||||
// // Pass the PNG to Tesseract for processing
|
||||
// exec("tesseract frame-" . $frame->getMetadata('pts') . ".png output");
|
||||
// }
|
||||
|
||||
// // Read the output from Tesseract
|
||||
// $text = file_get_contents("output.txt");
|
||||
|
||||
// // Do something with the text from Tesseract
|
||||
// echo $text;
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Conductors\ShortlinkConductor;
|
||||
use App\Enum\HttpResponseCodes;
|
||||
use App\Http\Requests\ShortlinkRequest;
|
||||
use App\Models\Shortlink;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ShortlinkController extends ApiController
|
||||
{
|
||||
/**
|
||||
* ApplicationController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth:sanctum')
|
||||
->only(['store','update','destroy']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
list($collection, $total) = ShortlinkConductor::request($request);
|
||||
|
||||
return $this->respondAsResource(
|
||||
$collection,
|
||||
['isCollection' => true,
|
||||
'appendData' => ['total' => $total]
|
||||
],
|
||||
function ($options) {
|
||||
return $options['total'] === 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @param \App\Models\Shortlink $shortlink The request shortlink.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Request $request, Shortlink $shortlink)
|
||||
{
|
||||
if (ShortlinkConductor::viewable($shortlink) === true) {
|
||||
return $this->respondAsResource(ShortlinkConductor::model($request, $shortlink));
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new media resource
|
||||
*
|
||||
* @param \App\Http\Requests\ShortlinkRequest $request The shortlink.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(ShortlinkRequest $request)
|
||||
{
|
||||
if (ShortlinkConductor::creatable() === true) {
|
||||
$shortlink = Shortlink::create($request->all());
|
||||
|
||||
return $this->respondAsResource(
|
||||
ShortlinkConductor::model($request, $shortlink),
|
||||
['respondCode' => HttpResponseCodes::HTTP_ACCEPTED]
|
||||
);
|
||||
}//end if
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the media resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\ShortlinkRequest $request The update request.
|
||||
* @param \App\Models\Shortlink $shortlink The specified shortlink.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(ShortlinkRequest $request, Shortlink $shortlink)
|
||||
{
|
||||
if (ShortlinkConductor::updatable($shortlink) === true) {
|
||||
$shortlink->update($request->all());
|
||||
return $this->respondAsResource(ShortlinkConductor::model($request, $shortlink));
|
||||
}//end if
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \App\Models\Shortlink $shortlink Specified shortlink.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Shortlink $shortlink)
|
||||
{
|
||||
if (ShortlinkConductor::destroyable($shortlink) === true) {
|
||||
$shortlink->delete();
|
||||
return $this->respondNoContent();
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
}
|
||||
@@ -1,369 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Conductors\EventConductor;
|
||||
use App\Enum\HttpResponseCodes;
|
||||
use App\Http\Requests\UserRequest;
|
||||
use App\Http\Requests\UserForgotPasswordRequest;
|
||||
use App\Http\Requests\UserRegisterRequest;
|
||||
use App\Http\Requests\UserResendVerifyEmailRequest;
|
||||
use App\Http\Requests\UserResetPasswordRequest;
|
||||
use App\Http\Requests\UserVerifyEmailRequest;
|
||||
use App\Jobs\SendEmailJob;
|
||||
use App\Mail\ChangedEmail;
|
||||
use App\Mail\ChangedPassword;
|
||||
use App\Mail\ChangeEmailVerify;
|
||||
use App\Mail\ForgotPassword;
|
||||
use App\Mail\EmailVerify;
|
||||
use App\Models\User;
|
||||
use App\Models\UserCode;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use App\Conductors\UserConductor;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||
|
||||
class UserController extends ApiController
|
||||
{
|
||||
/**
|
||||
* ApplicationController constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth:sanctum')
|
||||
->except([
|
||||
'index',
|
||||
'show',
|
||||
'register',
|
||||
'exists',
|
||||
'forgotPassword',
|
||||
'resetPassword',
|
||||
'verifyEmail',
|
||||
'resendVerifyEmailCode',
|
||||
'eventList',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
list($collection, $total) = UserConductor::request($request);
|
||||
|
||||
return $this->respondAsResource(
|
||||
$collection,
|
||||
['isCollection' => true,
|
||||
'appendData' => ['total' => $total]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created user in the database.
|
||||
*
|
||||
* @param \App\Http\Requests\UserRequest $request The endpoint request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(UserRequest $request)
|
||||
{
|
||||
if (UserConductor::creatable() === true) {
|
||||
$user = User::create($request->all());
|
||||
return $this->respondAsResource(
|
||||
UserConductor::model($request, $user),
|
||||
['respondCode' => HttpResponseCodes::HTTP_CREATED]
|
||||
);
|
||||
} else {
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified user.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request The endpoint request.
|
||||
* @param \App\Models\User $user The user model.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Request $request, User $user)
|
||||
{
|
||||
if (UserConductor::viewable($user) === true) {
|
||||
return $this->respondAsResource(UserConductor::model($request, $user));
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \App\Http\Requests\UserRequest $request The user update request.
|
||||
* @param \App\Models\User $user The specified user.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(UserRequest $request, User $user)
|
||||
{
|
||||
if (UserConductor::updatable($user) === true) {
|
||||
$input = [];
|
||||
$updatable = ['first_name', 'last_name', 'email', 'phone', 'password', 'display_name'];
|
||||
|
||||
if ($request->user()->hasPermission('admin/user') === true) {
|
||||
$updatable = array_merge($updatable, ['email_verified_at']);
|
||||
}
|
||||
|
||||
$input = $request->only($updatable);
|
||||
if (array_key_exists('password', $input) === true) {
|
||||
$input['password'] = Hash::make($request->input('password'));
|
||||
}
|
||||
|
||||
$user->update($input);
|
||||
|
||||
return $this->respondAsResource(UserConductor::model($request, $user));
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the user from the database.
|
||||
*
|
||||
* @param \App\Models\User $user The specified user.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(User $user)
|
||||
{
|
||||
if (UserConductor::destroyable($user) === true) {
|
||||
$user->delete();
|
||||
return $this->respondNoContent();
|
||||
}
|
||||
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new user
|
||||
*
|
||||
* @param \App\Http\Requests\UserRegisterRequest $request The register user request.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function register(UserRegisterRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$userData = $request->only([
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
'phone',
|
||||
'password',
|
||||
'display_name',
|
||||
]);
|
||||
|
||||
$userData['password'] = Hash::make($userData['password']);
|
||||
|
||||
$user = User::where('email', $request->input('email'))
|
||||
->whereNull('password')
|
||||
->first();
|
||||
|
||||
if ($user === null) {
|
||||
$user = User::create($userData);
|
||||
} else {
|
||||
unset($userData['email']);
|
||||
$user->update($userData);
|
||||
}//end if
|
||||
|
||||
$code = $user->codes()->create([
|
||||
'action' => 'verify-email',
|
||||
]);
|
||||
|
||||
dispatch((new SendEmailJob($user->email, new EmailVerify($user, $code->code))))->onQueue('mail');
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Check your email for a welcome code.'
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'message' => 'A server error occurred. Please try again later' . $e
|
||||
], 500);
|
||||
}//end try
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new reset password code
|
||||
*
|
||||
* @param \App\Http\Requests\UserForgotPasswordRequest $request The reset password request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function forgotPassword(UserForgotPasswordRequest $request)
|
||||
{
|
||||
$user = User::where('email', $request->input('email'))->first();
|
||||
if ($user !== null) {
|
||||
$user->codes()->where('action', 'reset-password')->delete();
|
||||
$code = $user->codes()->create([
|
||||
'action' => 'reset-password'
|
||||
]);
|
||||
|
||||
dispatch((new SendEmailJob($user->email, new ForgotPassword($user, $code->code))))->onQueue('mail');
|
||||
return $this->respondNoContent();
|
||||
}
|
||||
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a user password
|
||||
*
|
||||
* @param \App\Http\Requests\UserResetPasswordRequest $request The reset password request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function resetPassword(UserResetPasswordRequest $request)
|
||||
{
|
||||
UserCode::clearExpired();
|
||||
|
||||
$code = UserCode::where('code', $request->input('code'))->where('action', 'reset-password')->first();
|
||||
if ($code !== null) {
|
||||
$user = $code->user()->first();
|
||||
|
||||
$code->delete();
|
||||
$user->codes()->where('action', 'verify-email')->delete();
|
||||
|
||||
$user->password = Hash::make($request->input('password'));
|
||||
|
||||
if ($user->email_verified_at === null) {
|
||||
$user->email_verified_at = now();
|
||||
}
|
||||
|
||||
$user->save();
|
||||
|
||||
dispatch((new SendEmailJob($user->email, new ChangedPassword($user))))->onQueue('mail');
|
||||
return $this->respondNoContent();
|
||||
}
|
||||
|
||||
return $this->respondError([
|
||||
'code' => 'The code was not found or has expired.'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify an email code
|
||||
*
|
||||
* @param \App\Http\Requests\UserVerifyEmailRequest $request The verify email request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function verifyEmail(UserVerifyEmailRequest $request)
|
||||
{
|
||||
UserCode::clearExpired();
|
||||
|
||||
$code = UserCode::where('code', $request->input('code'))->where('action', 'verify-email')->first();
|
||||
if ($code !== null) {
|
||||
$user = $code->user()->first();
|
||||
$new_email = $code->data;
|
||||
|
||||
if ($new_email === null) {
|
||||
if ($user->email_verified_at === null) {
|
||||
$user->email_verified_at = now();
|
||||
}
|
||||
} else {
|
||||
dispatch((new SendEmailJob($user->email, new ChangedEmail($user, $user->email, $new_email))))
|
||||
->onQueue('mail');
|
||||
|
||||
$user->email = $new_email;
|
||||
$user->email_verified_at = now();
|
||||
}
|
||||
|
||||
$code->delete();
|
||||
$user->save();
|
||||
|
||||
return $this->respondNoContent();
|
||||
}//end if
|
||||
|
||||
return $this->respondWithErrors([
|
||||
'code' => 'The code was not found or has expired.'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resend a new verify email
|
||||
*
|
||||
* @param \App\Http\Requests\UserResendVerifyEmailRequest $request The resend verify email request.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function resendVerifyEmail(UserResendVerifyEmailRequest $request): JsonResponse
|
||||
{
|
||||
UserCode::clearExpired();
|
||||
|
||||
$user = User::where('email', $request->input('email'))->first();
|
||||
if ($user !== null) {
|
||||
$code = $user->codes()->where('action', 'verify-email')->first();
|
||||
$code->regenerate();
|
||||
$code->save();
|
||||
|
||||
if ($code->data === null) {
|
||||
dispatch((new SendEmailJob($user->email, new EmailVerify($user, $code->code))))->onQueue('mail');
|
||||
} else {
|
||||
dispatch((new SendEmailJob($user->email, new ChangeEmailVerify($user, $code->code, $code->data))))
|
||||
->onQueue('mail');
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'Verify email sent if user registered and required']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resend verification email
|
||||
*
|
||||
* @param \App\Http\Requests\UserResendVerifyEmailRequest $request The resend user request.
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function resendVerifyEmailCode(UserResendVerifyEmailRequest $request)
|
||||
{
|
||||
$user = User::where('email', $request->input('email'))->first();
|
||||
if ($user !== null) {
|
||||
$user->codes()->where('action', 'verify-email')->delete();
|
||||
|
||||
if ($user->email_verified_at === null) {
|
||||
$code = $user->codes()->create([
|
||||
'action' => 'verify-email'
|
||||
]);
|
||||
|
||||
dispatch((new SendEmailJob($user->email, new EmailVerify($user, $code->code))))->onQueue('mail');
|
||||
}
|
||||
|
||||
return $this->respondNoContent();
|
||||
}
|
||||
|
||||
return $this->respondNotFound();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a JSON event list of a user.
|
||||
*
|
||||
* @param Request $request The http request.
|
||||
* @param User $user The specified user.
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function eventList(Request $request, User $user): JsonResponse
|
||||
{
|
||||
if (
|
||||
$request->user() !== null && (
|
||||
$request->user() === $user || $request->user()->hasPermission('admin/events') === true
|
||||
)
|
||||
) {
|
||||
$collection = $user->events;
|
||||
$total = $collection->count();
|
||||
|
||||
$collection = EventConductor::collection($request, $collection);
|
||||
return $this->respondAsResource(
|
||||
$collection,
|
||||
['isCollection' => true,
|
||||
'appendData' => ['total' => $total]
|
||||
]
|
||||
);
|
||||
} else {
|
||||
return $this->respondForbidden();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,5 @@ use Illuminate\Routing\Controller as BaseController;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests;
|
||||
use ValidatesRequests;
|
||||
use AuthorizesRequests, ValidatesRequests;
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ class Kernel extends HttpKernel
|
||||
\Illuminate\Http\Middleware\HandleCors::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
// \App\Http\Middleware\TrimStrings::class,
|
||||
// \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -40,19 +40,15 @@ class Kernel extends HttpKernel
|
||||
|
||||
'api' => [
|
||||
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||
\Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
|
||||
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
// \App\Http\Middleware\ForceJsonResponse::class,
|
||||
\App\Http\Middleware\UnmangleRequest::class,
|
||||
'useSanctumGuard',
|
||||
\App\Http\Middleware\LogRequest::class,
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* The application's middleware aliases.
|
||||
*
|
||||
* Aliases may be used to conveniently assign middleware to routes and groups.
|
||||
* Aliases may be used instead of class names to conveniently assign middleware to routes and groups.
|
||||
*
|
||||
* @var array<string, class-string|string>
|
||||
*/
|
||||
@@ -63,11 +59,10 @@ class Kernel extends HttpKernel
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'unmangle' => \App\Http\Middleware\UnmangleRequest::class,
|
||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||
'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
|
||||
'signed' => \App\Http\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
'useSanctumGuard' => \App\Http\Middleware\UseSanctumGuard::class
|
||||
];
|
||||
}
|
||||
|
||||
@@ -3,21 +3,15 @@
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Auth\Middleware\Authenticate as Middleware;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class Authenticate extends Middleware
|
||||
{
|
||||
/**
|
||||
* Get the path the user should be redirected to when they are not authenticated.
|
||||
*
|
||||
* @param mixed $request Request.
|
||||
* @return ?string
|
||||
*/
|
||||
protected function redirectTo(mixed $request): ?string
|
||||
protected function redirectTo(Request $request): ?string
|
||||
{
|
||||
if ($request->expectsJson() === false) {
|
||||
return route('login');
|
||||
}
|
||||
|
||||
return null;
|
||||
return $request->expectsJson() ? null : route('login');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ForceJsonResponse
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
$request->headers->set('Accept', 'application/json');
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Models\AnalyticsItemRequest;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class LogRequest
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Illuminate\Http\Request $request HTTP Request.
|
||||
* @param \Closure $next Closure.
|
||||
* @return Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
// Make it an after middleware
|
||||
$response = $next($request);
|
||||
|
||||
try {
|
||||
AnalyticsItemRequest::create([
|
||||
'type' => 'apirequest',
|
||||
'path' => $request->path(),
|
||||
]);
|
||||
|
||||
return $response;
|
||||
} catch (\Error $e) {
|
||||
report($e);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,28 +2,25 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class RedirectIfAuthenticated
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request $request Request.
|
||||
* @param \Closure $next Closure.
|
||||
* @param string|null ...$guards Guards.
|
||||
* @return Response
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, string ...$guards): Response
|
||||
{
|
||||
$guards = empty($guards) === true ? [null] : $guards;
|
||||
$guards = empty($guards) ? [null] : $guards;
|
||||
|
||||
foreach ($guards as $guard) {
|
||||
if (Auth::guard($guard)->check() === true) {
|
||||
if (Auth::guard($guard)->check()) {
|
||||
return redirect(RouteServiceProvider::HOME);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,12 @@ class TrustProxies extends Middleware
|
||||
/**
|
||||
* The headers that should be used to detect proxies.
|
||||
*
|
||||
* @var integer
|
||||
* @var int
|
||||
*/
|
||||
// @codingStandardsIgnoreStart
|
||||
protected $headers = (Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO | Request::HEADER_X_FORWARDED_AWS_ELB);
|
||||
// @codingStandardsIgnoreEnd
|
||||
protected $headers =
|
||||
Request::HEADER_X_FORWARDED_FOR |
|
||||
Request::HEADER_X_FORWARDED_HOST |
|
||||
Request::HEADER_X_FORWARDED_PORT |
|
||||
Request::HEADER_X_FORWARDED_PROTO |
|
||||
Request::HEADER_X_FORWARDED_AWS_ELB;
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class UnmangleRequest
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request $request Request.
|
||||
* @param \Closure $next Next.
|
||||
* @param string|null ...$guards Guards.
|
||||
* @return Response response.
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, string ...$guards): Response
|
||||
{
|
||||
if (isset($_SERVER['QUERY_STRING']) === true) {
|
||||
$params = $request->all();
|
||||
|
||||
$string = $_SERVER['QUERY_STRING'];
|
||||
$parts = explode('&', $string);
|
||||
foreach ($parts as $part) {
|
||||
$key = $part;
|
||||
$splitPos = strpos($key, '=');
|
||||
if ($splitPos !== false) {
|
||||
$key = urldecode(substr($key, 0, $splitPos));
|
||||
}
|
||||
|
||||
$replace_key = str_replace('.', '_', $key);
|
||||
if (strpos($key, '.') !== false && array_key_exists($replace_key, $params) === true) {
|
||||
$params[$key] = $params[$replace_key];
|
||||
unset($params[$replace_key]);
|
||||
}
|
||||
}
|
||||
|
||||
$request->replace($params);
|
||||
}//end if
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class UseSanctumGuard
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request $request Request object.
|
||||
* @param \Closure $next Closure object.
|
||||
* @return Response
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
Auth::shouldUse('sanctum');
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class AnalyticsRequest extends BaseRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to POST requests.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function postRules(): array
|
||||
{
|
||||
return [
|
||||
'type' => 'required|string',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to PUT request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function putRules(): array
|
||||
{
|
||||
return [
|
||||
'type' => 'string',
|
||||
'useragent' => 'string',
|
||||
'ip' => 'ipv4|ipv6',
|
||||
'session' => 'number',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class ArticleRequest extends BaseRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to POST requests.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function postRules(): array
|
||||
{
|
||||
return [
|
||||
'slug' => 'required|string|min:6|unique:articles',
|
||||
'title' => 'required|string|min:6|max:255',
|
||||
'publish_at' => 'required|date',
|
||||
'user_id' => 'required|uuid|exists:users,id',
|
||||
'content' => 'required|string|min:6',
|
||||
'hero' => 'required|uuid|exists:media,id',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to PUT request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function putRules(): array
|
||||
{
|
||||
return [
|
||||
'slug' => [
|
||||
'string',
|
||||
'min:6',
|
||||
Rule::unique('articles')->ignoreModel($this->article),
|
||||
],
|
||||
'title' => 'string|min:6|max:255',
|
||||
'publish_at' => 'date',
|
||||
'user_id' => 'uuid|exists:users,id',
|
||||
'content' => 'string|min:6',
|
||||
'hero' => 'uuid|exists:media,id',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class AuthLoginRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'email' => 'required|string|min:6|max:255',
|
||||
'password' => 'required|string|min:6',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class BaseRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
if (request()->isMethod('post') === true && method_exists($this, 'postAuthorize') === true) {
|
||||
return $this->postAuthorize();
|
||||
} elseif (
|
||||
(
|
||||
request()->isMethod('put') === true || request()->isMethod('patch') === true
|
||||
) && method_exists($this, 'putAuthorize') === true
|
||||
) {
|
||||
return $this->putAuthorize();
|
||||
} elseif (request()->isMethod('delete') === true && method_exists($this, 'destroyAuthorize') === true) {
|
||||
return $this->deleteAuthorize();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = [];
|
||||
|
||||
if (method_exists($this, 'baseRules') === true) {
|
||||
$rules = $this->baseRules();
|
||||
}
|
||||
|
||||
if (method_exists($this, 'postRules') === true && request()->isMethod('post') === true) {
|
||||
$rules = $this->mergeRules($rules, $this->postRules());
|
||||
} elseif (
|
||||
method_exists($this, 'putRules') === true && (
|
||||
request()->isMethod('put') === true || request()->isMethod('patch') === true
|
||||
)
|
||||
) {
|
||||
$rules = $this->mergeRules($rules, $this->putRules());
|
||||
} elseif (method_exists($this, 'destroyRules') === true && request()->isMethod('delete') === true) {
|
||||
$rules = $this->mergeRules($rules, $this->destroyRules());
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge two collections of rules.
|
||||
*
|
||||
* @param array $collection1 The first collection of rules.
|
||||
* @param array $collection2 The second collection of rules to merge.
|
||||
* @return array
|
||||
*/
|
||||
private function mergeRules(array $collection1, array $collection2): array
|
||||
{
|
||||
$rules = [];
|
||||
|
||||
foreach ($collection1 as $key => $ruleset) {
|
||||
if (array_key_exists($key, $collection2) === true) {
|
||||
if (is_string($collection1[$key]) === true && is_string($collection2[$key]) === true) {
|
||||
$rules[$key] = $collection1[$key] . '|' . $collection2[$key];
|
||||
} else {
|
||||
$key_ruleset = [];
|
||||
|
||||
if (is_array($collection1[$key]) === true) {
|
||||
$key_ruleset = $collection1[$key];
|
||||
} elseif (is_string($collection1[$key]) === true) {
|
||||
$key_ruleset = explode('|', $collection1[$key]);
|
||||
}
|
||||
|
||||
if (is_array($collection2[$key]) === true) {
|
||||
$key_ruleset = array_merge($key_ruleset, $collection2[$key]);
|
||||
} elseif (is_string($collection2[$key]) === true) {
|
||||
$key_ruleset = array_merge($key_ruleset, explode('|', $collection2[$key]));
|
||||
}
|
||||
|
||||
if (count($key_ruleset) > 0) {
|
||||
$rules[$key] = $key_ruleset;
|
||||
}
|
||||
}//end if
|
||||
} else {
|
||||
$rules[$key] = $ruleset;
|
||||
}//end if
|
||||
}//end foreach
|
||||
|
||||
foreach ($collection2 as $key => $ruleset) {
|
||||
if (array_key_exists($key, $rules) === false) {
|
||||
$rules[$key] = $collection2[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Rules\Recaptcha;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ContactSendRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'required|max:255',
|
||||
'email' => 'required|email|max:255',
|
||||
'content' => 'required|max:2000',
|
||||
// 'captcha_token' => [new Recaptcha()],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class EventRequest extends BaseRequest
|
||||
{
|
||||
/**
|
||||
* Apply the base rules to this request
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function baseRules(): array
|
||||
{
|
||||
return [
|
||||
'title' => 'min:6',
|
||||
'location' => [
|
||||
Rule::in(['online', 'physical']),
|
||||
],
|
||||
'address' => 'string|nullable',
|
||||
'start_at' => 'date',
|
||||
'end_at' => 'date|after:start_date',
|
||||
'publish_at' => 'date|nullable',
|
||||
'status' => [
|
||||
Rule::in(['draft', 'soon', 'open', 'closed', 'cancelled', 'scheduled', 'full']),
|
||||
],
|
||||
'registration_type' => [
|
||||
Rule::in(['none', 'email', 'link', 'message']),
|
||||
],
|
||||
'registration_data' => [
|
||||
Rule::when(strcasecmp('email', $this->attributes->get('registration_type')) == 0, 'required|email'),
|
||||
Rule::when(strcasecmp('link', $this->attributes->get('registration_type')) == 0, 'required|url'),
|
||||
Rule::when(strcasecmp('message', $this->attributes->get('registration_type')) == 0, 'required|message'),
|
||||
],
|
||||
'hero' => 'uuid|exists:media,id',
|
||||
'location_url' => 'sometimes|string|max:255',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the additional POST base rules to this request
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
protected function postRules(): array
|
||||
{
|
||||
return [
|
||||
'title' => 'required',
|
||||
'location' => 'required',
|
||||
'address' => 'required_if:location,physical',
|
||||
'start_at' => 'required',
|
||||
'end_at' => 'required',
|
||||
'status' => 'required',
|
||||
'registration_type' => 'required',
|
||||
'hero' => 'required',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class MediaRequest extends BaseRequest
|
||||
{
|
||||
/**
|
||||
* POST request rules
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function postRules(): array
|
||||
{
|
||||
return [
|
||||
'job_id' => [
|
||||
Rule::requiredIf(function () {
|
||||
return request()->has('chunk') && request('chunk') != 1;
|
||||
}),
|
||||
'string',
|
||||
],
|
||||
'name' => [
|
||||
Rule::requiredIf(function () {
|
||||
return request()->has('chunk') && request('chunk') == 1;
|
||||
}),
|
||||
'string',
|
||||
],
|
||||
'chunk' => 'required_with:chunk_count|integer|min:1|max:999|lte:chunk_count',
|
||||
'chunk_count' => 'required_with:chunk|integer|min:1',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class ShortlinkRequest extends BaseRequest
|
||||
{
|
||||
/**
|
||||
* Apply the additional POST base rules to this request
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function postRules(): array
|
||||
{
|
||||
return [
|
||||
'code' => 'required|string|max:255|min:2|unique:shortlinks',
|
||||
'url' => 'required|string|max:255|min:2',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to PUT request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function putRules(): array
|
||||
{
|
||||
$shortlink = $this->route('shortlink');
|
||||
|
||||
return [
|
||||
'code' => ['required', 'string', 'max:255', 'min:2', Rule::unique('shortlinks')->ignore($shortlink->id)],
|
||||
'url' => 'required|string|max:255|min:2',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Rules\Recaptcha;
|
||||
|
||||
class SubscriptionRequest extends BaseRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function postRules(): array
|
||||
{
|
||||
return [
|
||||
'email' => 'required|email|unique:subscriptions',
|
||||
// 'captcha_token' => [new Recaptcha()],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function destroyRules(): array
|
||||
{
|
||||
return [
|
||||
'email' => 'required|email',
|
||||
// 'captcha_token' => [new Recaptcha()],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the custom error messages.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'email.unique' => 'This email address has already subscribed',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Rules\Recaptcha;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UserForgotPasswordRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'email' => 'required|exists:users,email',
|
||||
// 'captcha_token' => [new Recaptcha()],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Rules\Uniqueish;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UserRegisterRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'display_name' => ['required','string','max:255', new Uniqueish('users')],
|
||||
'email' => 'required|string|email|max:255|unique:users',
|
||||
'password' => 'required|string|min:8',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Rules\RequiredIfAny;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\Rules\RequiredIf;
|
||||
use App\Rules\Uniqueish;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class UserRequest extends BaseRequest
|
||||
{
|
||||
/**
|
||||
* Apply the additional POST base rules to this request
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function postRules(): array
|
||||
{
|
||||
$user = auth()->user();
|
||||
$isAdminUser = $user->hasPermission('admin/users');
|
||||
|
||||
return [
|
||||
'first_name' => (
|
||||
$isAdminUser === true ? 'required_with:last_name,display_name,phone' : 'required'
|
||||
) . '|string|max:255|min:2',
|
||||
'last_name' => (
|
||||
$isAdminUser === true ? 'required_with:first_name,display_name,phone' : 'required'
|
||||
) . '|string|max:255|min:2',
|
||||
'display_name' => [
|
||||
$isAdminUser === true ? 'required_with:first_name,last_name,phone' : 'required',
|
||||
'string',
|
||||
'max:255',
|
||||
new Uniqueish('users')
|
||||
],
|
||||
'email' => 'required|string|email|max:255|unique:users',
|
||||
'phone' => ['string', 'regex:/^(\+|00)?[0-9][0-9 \-\(\)\.]{7,32}$/'],
|
||||
'email_verified_at' => 'date'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to PUT request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function putRules(): array
|
||||
{
|
||||
$user = auth()->user();
|
||||
$ruleUser = $this->route('user');
|
||||
$isAdminUser = $user->hasPermission('admin/users');
|
||||
|
||||
$requiredIfFieldsPresent = function (array $fields) use ($ruleUser): RequiredIf {
|
||||
return new RequiredIf(function () use ($fields, $ruleUser) {
|
||||
$input = $this->all();
|
||||
$values = Arr::only($input, $fields);
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
if ($value !== null && $value !== '') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$fields = array_diff($fields, array_keys($values));
|
||||
|
||||
foreach ($fields as $field) {
|
||||
if ($ruleUser->$field !== '') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
return [
|
||||
'first_name' => [
|
||||
'sometimes',
|
||||
$isAdminUser === true ? $requiredIfFieldsPresent(['last_name', 'display_name', 'phone']) : 'required',
|
||||
'string',
|
||||
'between:2,255',
|
||||
],
|
||||
'last_name' => [
|
||||
'sometimes',
|
||||
$isAdminUser === true ? $requiredIfFieldsPresent(['first_name', 'last_name', 'phone']) : 'required',
|
||||
'string',
|
||||
'between:2,255',
|
||||
],
|
||||
'display_name' => [
|
||||
'sometimes',
|
||||
$isAdminUser === true ? $requiredIfFieldsPresent(['first_name', 'display_name', 'phone']) : 'required',
|
||||
'string',
|
||||
'between:2,255',
|
||||
(new Uniqueish('users', 'display_name'))->ignore($ruleUser->id)
|
||||
],
|
||||
'email' => [
|
||||
'string',
|
||||
'email',
|
||||
'max:255',
|
||||
Rule::unique('users')->ignore($ruleUser->id)->when(
|
||||
$this->email !== $ruleUser->email,
|
||||
function ($query) {
|
||||
return $query->where('email', $this->email);
|
||||
}
|
||||
),
|
||||
],
|
||||
'phone' => ['nullable', 'regex:/^(\+|00)?[0-9][0-9 \-\(\)\.]{7,32}$/'],
|
||||
'password' => "nullable|string|min:8"
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Rules\Recaptcha;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UserResendVerifyEmailRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'email' => 'required|exists:users,email',
|
||||
// 'captcha_token' => [new Recaptcha()],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Rules\Recaptcha;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UserResetPasswordRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'code' => 'required|digits:6',
|
||||
'password' => 'required|string|min:8',
|
||||
// 'captcha_token' => [new Recaptcha()],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Rules\Recaptcha;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UserVerifyEmailRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'code' => 'required|digits:6',
|
||||
// 'captcha_token' => [new Recaptcha()],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,393 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Models\Media;
|
||||
use App\Models\MediaJob;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use FFMpeg;
|
||||
use FFMpeg\Coordinate\Dimension;
|
||||
use FFMpeg\FFProbe;
|
||||
use FFMpeg\Format\VideoInterface;
|
||||
use Intervention\Image\Facades\Image;
|
||||
|
||||
/** @property on $format */
|
||||
class MediaWorkerJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* MediaJob item
|
||||
*
|
||||
* @var MediaJob
|
||||
*/
|
||||
protected $mediaJob;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param MediaJob $mediaJob The mediaJob model.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(MediaJob $mediaJob)
|
||||
{
|
||||
$this->mediaJob = $mediaJob;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$media = $this->mediaJob->media()->first();
|
||||
$newMedia = false;
|
||||
$data = json_decode($this->mediaJob->data, true);
|
||||
|
||||
try {
|
||||
// FILE
|
||||
if (array_key_exists('file', $data) === true) {
|
||||
if (file_exists($data['file']) === false) {
|
||||
$this->throwMediaJobFailure('temporary upload file no longer exists');
|
||||
}
|
||||
|
||||
// convert HEIC files to JPG
|
||||
$fileExtension = File::extension($data['file']);
|
||||
if ($fileExtension === 'heic') {
|
||||
$this->mediaJob->setStatusProcessing(0, 0, 'converting image');
|
||||
|
||||
// Get the path without the file name
|
||||
$uploadedFileDirectory = dirname($data['file']);
|
||||
|
||||
// Convert the HEIC file to JPG
|
||||
$jpgFileName = pathinfo($data['file'], PATHINFO_FILENAME) . '.jpg';
|
||||
$jpgFilePath = $uploadedFileDirectory . '/' . $jpgFileName;
|
||||
if (file_exists($jpgFilePath) === true) {
|
||||
$this->throwMediaJobFailure('file already exists on server');
|
||||
}
|
||||
|
||||
Image::make($data['file'])->save($jpgFilePath);
|
||||
|
||||
// Update the uploaded file path and file name
|
||||
unlink($data['file']);
|
||||
$data['file'] = $jpgFileName;
|
||||
}//end if
|
||||
|
||||
// get security
|
||||
$security = [];
|
||||
if ($media === null) {
|
||||
if (array_key_exists('security', $data) === true) {
|
||||
$security = $data['security'];
|
||||
}
|
||||
} else {
|
||||
$security['type'] = $media->security_type;
|
||||
$security['data'] = $media->security_data;
|
||||
}
|
||||
|
||||
// get storage
|
||||
$storage = '';
|
||||
if ($media === null) {
|
||||
if (array_key_exists('storage', $data) === true) {
|
||||
$storage = $data['storage'];
|
||||
}
|
||||
} else {
|
||||
$storage = $media->storage;
|
||||
}
|
||||
|
||||
if ($storage === '') {
|
||||
if (count($security) === 0 || $security['type'] === '') {
|
||||
if (strpos($data['mime_type'], 'image/') === 0) {
|
||||
$storage = 'local';
|
||||
} else {
|
||||
$storage = 'cdn';
|
||||
}
|
||||
} else {
|
||||
$storage = 'private';
|
||||
}
|
||||
}
|
||||
|
||||
// Check if file already exists
|
||||
$exists = Storage::disk($storage)->exists($data['name']);
|
||||
if ($exists === true) {
|
||||
if (array_key_exists('noreplace', $data) === true && isTrue($data['noreplace']) === true) {
|
||||
$this->throwMediaJobFailure('file already exists on server');
|
||||
}
|
||||
}
|
||||
|
||||
if ($exists === true) {
|
||||
$pathInfo = pathinfo($data['name']);
|
||||
$basename = $pathInfo['filename'];
|
||||
$extension = $pathInfo['extension'];
|
||||
$index = 0;
|
||||
|
||||
do {
|
||||
$index++;
|
||||
$data['name'] = $basename . '-' . $index . '.' . $extension;
|
||||
} while (Storage::disk($storage)->exists($data['name']) === true);
|
||||
}
|
||||
|
||||
if ($media === null) {
|
||||
$newMedia = true;
|
||||
$media = new Media([
|
||||
'user_id' => $this->mediaJob->user_id,
|
||||
'title' => $data['title'],
|
||||
'name' => $data['name'],
|
||||
'mime_type' => $data['mime_type'],
|
||||
'size' => $data['size'],
|
||||
'security_type' => $data['security']['type'],
|
||||
'security_data' => $data['security']['data'],
|
||||
'storage' => $storage,
|
||||
]);
|
||||
}//end if
|
||||
|
||||
$media->setStagingFile($data['file']);
|
||||
} else {
|
||||
if ($media === null) {
|
||||
$this->throwMediaJobFailure('The media item no longer exists');
|
||||
}
|
||||
}//end if
|
||||
|
||||
if (array_key_exists('transform', $data) === true) {
|
||||
$media->createStagingFile();
|
||||
|
||||
// Modifications
|
||||
if (strpos($media->mime_type, 'image/') === 0) {
|
||||
$modified = false;
|
||||
$image = Image::make($media->getStagingFilePath());
|
||||
|
||||
// ROTATE
|
||||
if (array_key_exists("rotate", $data['transform']) === true) {
|
||||
$rotate = intval($data['transform']['rotate']);
|
||||
if ($rotate !== 0) {
|
||||
$this->mediaJob->setStatusProcessing(0, 0, 'rotating image');
|
||||
$image = $image->rotate($rotate);
|
||||
$modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
// FLIP-H/V
|
||||
if (array_key_exists('flip', $data['transform']) === true) {
|
||||
if (stripos($data['transform']['flip'], 'h') !== false) {
|
||||
$this->mediaJob->setStatusProcessing(0, 0, 'flipping image');
|
||||
$image = $image->flip('h');
|
||||
$modified = true;
|
||||
}
|
||||
|
||||
if (stripos($data['transform']['flip'], 'v') !== false) {
|
||||
$this->mediaJob->setStatusProcessing(0, 0, 'flipping image');
|
||||
$image = $image->flip('v');
|
||||
$modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
// CROP
|
||||
if (array_key_exists("crop", $data['transform']) === true) {
|
||||
$cropData = $data['transform']['crop'];
|
||||
$width = intval(arrayDefaultValue("width", $cropData, $image->getWidth()));
|
||||
$height = intval(arrayDefaultValue("height", $cropData, $image->getHeight()));
|
||||
$x = intval(arrayDefaultValue("x", $cropData, 0));
|
||||
$y = intval(arrayDefaultValue("y", $cropData, 0));
|
||||
|
||||
$this->mediaJob->setStatusProcessing(0, 0, 'cropping image');
|
||||
$image = $image->crop($width, $height, $x, $y);
|
||||
$modified = true;
|
||||
}//end if
|
||||
|
||||
if ($modified === true) {
|
||||
$image->save();
|
||||
}
|
||||
} elseif (strpos($data['mime_type'], 'video/') === 0) {
|
||||
$stagingFilePath = $media->getStagingFilePath();
|
||||
$ffmpeg = FFMpeg\FFMpeg::create();
|
||||
$video = $ffmpeg->open($stagingFilePath);
|
||||
$format = $this->detectVideoFormat($stagingFilePath);
|
||||
$modified = false;
|
||||
|
||||
if ($format === null) {
|
||||
$this->mediaJob->setStatusFailed('Unsupported video format');
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var FFMpeg\Media\Video::filters */
|
||||
$filters = $video->filters();
|
||||
|
||||
// ROTATE
|
||||
if (array_key_exists("rotate", $data['transform']) === true) {
|
||||
$rotate = intval($data['transform']['rotate']);
|
||||
$rotate = (($rotate % 360 + 360) % 360); // remove excess rotations
|
||||
$rotate = intval(round($rotate / 90) * 90); // round to nearest 90%
|
||||
|
||||
if ($rotate > 0) {
|
||||
$this->mediaJob->setStatusProcessing(0, 0, 'rotating video');
|
||||
|
||||
if ($rotate === 90) {
|
||||
$filters->rotate(FFMpeg\Filters\Video\RotateFilter::ROTATE_270);
|
||||
$modified = true;
|
||||
} elseif ($rotate === 180) {
|
||||
$filters->rotate(FFMpeg\Filters\Video\RotateFilter::ROTATE_180);
|
||||
$modified = true;
|
||||
} elseif ($rotate === 270) {
|
||||
$filters->rotate(FFMpeg\Filters\Video\RotateFilter::ROTATE_90);
|
||||
$modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FLIP-H/V
|
||||
if (array_key_exists('flip', $data['transform']) === true) {
|
||||
if (stripos($data['transform']['flip'], 'h') !== false) {
|
||||
$this->mediaJob->setStatusProcessing(0, 0, 'flipping video');
|
||||
$filters->hflip()->synchronize();
|
||||
$modified = true;
|
||||
}
|
||||
|
||||
if (stripos($data['transform']['flip'], 'v') !== false) {
|
||||
$this->mediaJob->setStatusProcessing(0, 0, 'flipping video');
|
||||
$filters->vflip()->synchronize();
|
||||
$modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
// CROP
|
||||
if (array_key_exists("crop", $data['transform']) === true) {
|
||||
$cropData = $data['transform']['crop'];
|
||||
$videoStream = $video->getStreams()->videos()->first();
|
||||
|
||||
$width = intval(arrayDefaultValue("width", $cropData, $videoStream->get('width')));
|
||||
$height = intval(arrayDefaultValue("height", $cropData, $videoStream->get('height')));
|
||||
$x = intval(arrayDefaultValue("x", $cropData, 0));
|
||||
$y = intval(arrayDefaultValue("y", $cropData, 0));
|
||||
|
||||
$cropDimension = new Dimension($width, $height);
|
||||
|
||||
$this->mediaJob->setStatusProcessing(0, 0, 'cropping video');
|
||||
$filters->crop($cropDimension, $x, $y)->synchronize();
|
||||
$modified = true;
|
||||
}//end if
|
||||
|
||||
$tempFilePath = generateTempFilePath(pathinfo($stagingFilePath, PATHINFO_EXTENSION));
|
||||
if (method_exists($format, 'on') === true) {
|
||||
$mediaJob = $this->mediaJob;
|
||||
$format->on('progress', function ($video, $format, $percentage) use ($mediaJob) {
|
||||
$mediaJob->setStatusProcessing($percentage, 100, 'transcoded');
|
||||
});
|
||||
}
|
||||
|
||||
if ($modified === true) {
|
||||
$video->save($format, $tempFilePath);
|
||||
$media->changeStagingFile($tempFilePath);
|
||||
}
|
||||
}//end if
|
||||
}//end if
|
||||
|
||||
// Update attributes
|
||||
if (array_key_exists('title', $data) === true) {
|
||||
$media->title = $data['title'];
|
||||
}
|
||||
|
||||
// Relocate file (if requested)
|
||||
if (array_key_exists('security', $data) === true && array_key_exists('type', $data['security']) === true) {
|
||||
$media->security_type = $data['security']['type'];
|
||||
$media->security_data = $data['security']['data'];
|
||||
}
|
||||
|
||||
if (array_key_exists('storage', $data) === true) {
|
||||
if ($media->storage !== $data['storage']) {
|
||||
$media->createStagingFile();
|
||||
Storage::disk($media->storage)->delete($media->name);
|
||||
$media->storage = $data['storage'];
|
||||
}
|
||||
}
|
||||
|
||||
// Finish media object
|
||||
if ($media->hasStagingFile() === true) {
|
||||
$this->mediaJob->setStatusProcessing(0, 0, 'transferring to cdn');
|
||||
$media->deleteFile();
|
||||
$media->saveStagingFile(true);
|
||||
}
|
||||
|
||||
$media->save();
|
||||
$this->mediaJob->media_id = $media->id;
|
||||
$this->mediaJob->setStatusComplete();
|
||||
} catch (\Exception $e) {
|
||||
if ($this->mediaJob->status !== 'failed') {
|
||||
$this->mediaJob->setStatusFailed('Unexpected server error occurred');
|
||||
}
|
||||
|
||||
if ($media !== null) {
|
||||
$media->deleteStagingFile();
|
||||
if ($newMedia === true) {
|
||||
$media->delete();
|
||||
}
|
||||
}
|
||||
|
||||
Log::error($e->getMessage() . "\n" . $e->getFile() . " - " . $e->getLine() . "\n" . $e->getTraceAsString());
|
||||
$this->fail($e);
|
||||
}//end try
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the format of a video using FFProbe
|
||||
*
|
||||
* @param string $videoPath The video file path.
|
||||
* @return VideoInterface | null
|
||||
*/
|
||||
public function detectVideoFormat(string $videoPath): VideoInterface | null
|
||||
{
|
||||
$ffprobe = FFProbe::create();
|
||||
|
||||
$videoStream = $ffprobe
|
||||
->streams($videoPath) // Provide the path to the video file
|
||||
->videos() // Filter video streams
|
||||
->first();
|
||||
|
||||
$codecName = $videoStream->get('codec_name');
|
||||
|
||||
$codecToFormatClass = [
|
||||
'h264' => 'FFMpeg\Format\Video\X264',
|
||||
'wmv2' => 'FFMpeg\Format\Video\WMV',
|
||||
'vp9' => 'FFMpeg\Format\Video\WebM',
|
||||
'theora' => 'FFMpeg\Format\Video\Ogg',
|
||||
'mpeg4' => 'FFMpeg\Format\Video\Mpeg4',
|
||||
// Add more mappings as needed
|
||||
];
|
||||
|
||||
if (isset($codecToFormatClass[$codecName]) === false) {
|
||||
Log::info("Unsupported codec: $codecName");
|
||||
return null;
|
||||
}
|
||||
|
||||
$formatClassName = $codecToFormatClass[$codecName];
|
||||
|
||||
if (class_exists($formatClassName) === false) {
|
||||
Log::info("Format class does not exist: $formatClassName");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new $formatClassName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set failure status of MediaJob and throw exception.
|
||||
*
|
||||
* @param string $error The failure message.
|
||||
* @return void
|
||||
*/
|
||||
private function throwMediaJobFailure(string $error): void
|
||||
{
|
||||
$this->mediaJob->setStatusFailed($error);
|
||||
throw new \Exception($error);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class SendEmailJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable;
|
||||
use InteractsWithQueue;
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* Mail to receipt
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $to;
|
||||
|
||||
/**
|
||||
* Mailable item
|
||||
*
|
||||
* @var Mailable
|
||||
*/
|
||||
public $mailable;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param string $to The email receipient.
|
||||
* @param Mailable $mailable The mailable.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $to, Mailable $mailable)
|
||||
{
|
||||
$this->to = $to;
|
||||
$this->mailable = $mailable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
Mail::to($this->to)->send($this->mailable);
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ChangeEmailVerify extends Mailable
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The user instance.
|
||||
*
|
||||
* @var \App\Models\User
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* The registration code.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $code;
|
||||
|
||||
/**
|
||||
* The new email address.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $new_email;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param User $user The user the email applies to.
|
||||
* @param integer $code The action code.
|
||||
* @param string $new_email The new email address.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(User $user, int $code, string $new_email)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->code = $code;
|
||||
$this->new_email = $new_email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Envelope
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: '👋🏻 Lets change your email!',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Content
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
view: 'emails.user.change_email_verify',
|
||||
text: 'emails.user.change_email_verify_plain',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ChangedEmail extends Mailable
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The user instance.
|
||||
*
|
||||
* @var \App\Models\User
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* The old email.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $old_email;
|
||||
|
||||
/**
|
||||
* The new email.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $new_email;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param User $user The user the email applies to.
|
||||
* @param string $old_email The previous email address.
|
||||
* @param string $new_email The new email address.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(User $user, string $old_email, string $new_email)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->old_email = $old_email;
|
||||
$this->new_email = $new_email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Envelope
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: '👍 Your email has been changed!',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Content
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
view: 'emails.user.changed_email',
|
||||
text: 'emails.user.changed_email_plain',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ChangedPassword extends Mailable
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The user instance.
|
||||
*
|
||||
* @var \App\Models\User
|
||||
*/
|
||||
public $user;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param User $user The user the email applies to.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Envelope
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: '👍 Your password has been changed!',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Content
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
view: 'emails.user.changed_password',
|
||||
text: 'emails.user.changed_password_plain',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class Contact extends Mailable
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The contact name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* The contact email.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $email;
|
||||
|
||||
/**
|
||||
* The contact content.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $content;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param string $name The contact name.
|
||||
* @param string $email The contact email.
|
||||
* @param string $content The contact content.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $name, string $email, string $content)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->email = $email;
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Envelope
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: config('contact.contact_subject'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Content
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
view: 'emails.user.contact',
|
||||
text: 'emails.user.contact_plain',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class EmailVerify extends Mailable
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The user instance.
|
||||
*
|
||||
* @var \App\Models\User
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* The registration code.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $code;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param User $user The user the email applies to.
|
||||
* @param integer $code The action code.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(User $user, int $code)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->code = $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Envelope
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: '👋🏻 Welcome to STEMMechanics!',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Content
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
view: 'emails.user.email_verify',
|
||||
text: 'emails.user.email_verify_plain',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ExceptionMail extends Mailable
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Envelope
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: 'Exception Mail',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Content
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
view: 'view.name',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attachments for the message.
|
||||
*
|
||||
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||
*/
|
||||
public function attachments(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ForgotPassword extends Mailable
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The user
|
||||
*
|
||||
* @var \App\Models\User
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* The reset code
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $code;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param User $user The user the email applies to.
|
||||
* @param integer $code The action code.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(User $user, int $code)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->code = $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Envelope
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: '🤦 Forgot your password?',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Content
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
view: 'emails.user.forgot_password',
|
||||
text: 'emails.user.forgot_password_plain',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class SubscriptionConfirm extends Mailable
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The email address.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $email;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param string $email The email address.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $email)
|
||||
{
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Envelope
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: '🗞️ You\'re on the mailing list!',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Content
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
view: 'emails.user.subscription_confirm',
|
||||
text: 'emails.user.subscription_confirm_plain',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class SubscriptionUnsubscribed extends Mailable
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
* The email address.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $email;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param string $email The email address.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $email)
|
||||
{
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message envelope.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Envelope
|
||||
*/
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
subject: 'You have been unsubscribed',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*
|
||||
* @return Illuminate\Mail\Mailables\Content
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
view: 'emails.user.subscription_unsubscribed',
|
||||
text: 'emails.user.subscription_unsubscribed_plain',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class AnalyticsItemRequest extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The table name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'analytics_requests';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'type',
|
||||
'path'
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Model Boot.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::creating(function (AnalyticsItemRequest $analytics) {
|
||||
if (isset($analytics->session_id) !== true) {
|
||||
$request = request();
|
||||
if ($request !== null) {
|
||||
$session = AnalyticsSession::where('ip', $request->ip())
|
||||
->where('useragent', $request->userAgent())
|
||||
->where('ended_at', '>=', now()->subMinutes(30))
|
||||
->first();
|
||||
if ($session === null) {
|
||||
$session = AnalyticsSession::create([
|
||||
'ip' => $request->ip(),
|
||||
'useragent' => $request->userAgent(),
|
||||
'ended_at' => now()
|
||||
]);
|
||||
} else {
|
||||
$session->update(['ended_at' => now()]);
|
||||
}
|
||||
|
||||
$analytics->session_id = $session->id;
|
||||
}
|
||||
}//end if
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Analytics Session model.
|
||||
*
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function session(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(AnalyticsSession::class, 'id', 'session_id');
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class AnalyticsSession extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'ip',
|
||||
'useragent',
|
||||
'ended_at'
|
||||
];
|
||||
|
||||
/**
|
||||
* Set the "useragent" attribute.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
*/
|
||||
public function setUseragentAttribute($value)
|
||||
{
|
||||
$this->attributes['useragent'] = $value !== null ? $value : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the related requests for this session.
|
||||
*
|
||||
* @return Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function requests(): HasMany {
|
||||
return $this->hasMany(AnalyticsItemRequest::class, 'session_id', 'id');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\HasAttachments;
|
||||
use App\Traits\HasGallery;
|
||||
use App\Traits\Uuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Article extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Uuids;
|
||||
use HasGallery;
|
||||
use HasAttachments;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'slug',
|
||||
'publish_at',
|
||||
'content',
|
||||
'user_id',
|
||||
'hero'
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Get the article user
|
||||
*
|
||||
* @return Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class Attachment extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'media_id',
|
||||
'private',
|
||||
];
|
||||
|
||||
/**
|
||||
* The default attributes.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $attributes = [
|
||||
'private' => false,
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Get the media for this attachment.
|
||||
*
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function media(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Media::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get associated Media object.
|
||||
*
|
||||
* @return null|Media
|
||||
*/
|
||||
public function getMediaAttribute(): ?Media
|
||||
{
|
||||
$mediaId = '0';
|
||||
$media = null;
|
||||
|
||||
if (Cache::has("attachment:{$this->id}:media") === true) {
|
||||
$mediaId = Cache::get("attachment:{$this->id}:media");
|
||||
} else {
|
||||
$media = $this->media()->first();
|
||||
if ($media === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$mediaId = $media->id;
|
||||
Cache::put("attachment:{$this->id}:media", $mediaId, now()->addDays(28));
|
||||
}
|
||||
|
||||
return Cache::remember("media:{$mediaId}", now()->addDays(28), function () use ($media) {
|
||||
if ($media !== null) {
|
||||
return $media;
|
||||
}
|
||||
|
||||
return $this->media()->first();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the media for this item.
|
||||
*
|
||||
* @param Media $media The media model.
|
||||
* @return void
|
||||
*/
|
||||
public function setMediaAttribute(Media $media): void
|
||||
{
|
||||
$this->media()->associate($media)->save();
|
||||
Cache::put("attachment:{$this->id}:media", $media->id, now()->addDays(28));
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\HasAttachments;
|
||||
use App\Traits\Uuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
|
||||
class Event extends Model
|
||||
{
|
||||
use HasAttachments;
|
||||
use HasFactory;
|
||||
use Uuids;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'location',
|
||||
'location_url',
|
||||
'address',
|
||||
'start_at',
|
||||
'end_at',
|
||||
'publish_at',
|
||||
'status',
|
||||
'registration_type',
|
||||
'registration_data',
|
||||
'hero',
|
||||
'content',
|
||||
'price',
|
||||
'ages',
|
||||
'open_at',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Get all the associated users.
|
||||
*
|
||||
* @return BelongsToMany
|
||||
*/
|
||||
public function users(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(User::class, 'event_user', 'event_id', 'user_id');
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Uuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class EventUser extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Uuids;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'event_id',
|
||||
'user_id',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Get the event for this attachment.
|
||||
*
|
||||
* @return Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function event(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Event::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user for this attachment.
|
||||
*
|
||||
* @return Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Uuids;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class Gallery extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Uuids;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'media_id',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Boot the model.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
$clearCache = function ($gallery) {
|
||||
Cache::forget("gallery:{$gallery->id}:media");
|
||||
};
|
||||
|
||||
static::saving($clearCache);
|
||||
static::deleting($clearCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get gallery addendum model.
|
||||
*
|
||||
* @return Illuminate\Database\Eloquent\Relations\MorphTo Addenum model.
|
||||
*/
|
||||
public function addendum(): MorphTo
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the media for this item.
|
||||
*
|
||||
* @return Illuminate\Database\Eloquent\Relations\BelongsTo The media model.
|
||||
*/
|
||||
public function media(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Media::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the media for this item.
|
||||
*
|
||||
* @return null|Media The media model.
|
||||
*/
|
||||
public function getMediaAttribute(): ?Media
|
||||
{
|
||||
$mediaId = '0';
|
||||
$media = null;
|
||||
|
||||
if (Cache::has("gallery:{$this->id}:media") === true) {
|
||||
$mediaId = Cache::get("gallery:{$this->id}:media");
|
||||
} else {
|
||||
$media = $this->media()->first();
|
||||
if ($media === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$mediaId = $media->id;
|
||||
Cache::put("gallery:{$this->id}:media", $mediaId, now()->addDays(28));
|
||||
}
|
||||
|
||||
return Cache::remember("media:{$mediaId}", now()->addDays(28), function () use ($media) {
|
||||
if ($media !== null) {
|
||||
return $media;
|
||||
}
|
||||
|
||||
return $this->media()->first();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the media for this item.
|
||||
*
|
||||
* @param Media $media The media model.
|
||||
* @return void
|
||||
*/
|
||||
public function setMediaAttribute(Media $media): void
|
||||
{
|
||||
$this->media()->associate($media)->save();
|
||||
Cache::put("gallery:{$this->id}:media", $media->id, now()->addDays(28));
|
||||
}
|
||||
}
|
||||
1064
app/Models/Media.php
1064
app/Models/Media.php
File diff suppressed because it is too large
Load Diff
@@ -1,239 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Jobs\MediaWorkerJob;
|
||||
use App\Traits\Uuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class MediaJob extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Uuids;
|
||||
|
||||
|
||||
/**
|
||||
* The default attributes.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $attributes = [
|
||||
'user_id' => null,
|
||||
'media_id' => null,
|
||||
'status' => '',
|
||||
'status_text' => '',
|
||||
'progress' => 0,
|
||||
'progress_max' => 0,
|
||||
'data' => '',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Set MediaJob status to failed.
|
||||
*
|
||||
* @param string $statusText The failed reason.
|
||||
* @return void
|
||||
*/
|
||||
public function setStatusFailed(string $statusText = ''): void
|
||||
{
|
||||
$this->setStatus('failed', $statusText, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MediaJob status to queued.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setStatusQueued(): void
|
||||
{
|
||||
$this->setStatus('queued', '', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MediaJob status to waiting.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setStatusWaiting(): void
|
||||
{
|
||||
$this->setStatus('waiting', '', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MediaJob status to processing.
|
||||
*
|
||||
* @param integer $progress The processing progress value.
|
||||
* @param integer $progressMax The processing progress maximum value.
|
||||
* @param string $statusText The processing status text.
|
||||
* @return void
|
||||
*/
|
||||
public function setStatusProcessing(int $progress = 0, int $progressMax = 0, string $statusText = ''): void
|
||||
{
|
||||
if ($statusText === '') {
|
||||
$statusText = $this->status_text;
|
||||
}
|
||||
|
||||
$this->setStatus('processing', $statusText, $progress, $progressMax);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MediaJob status to complete.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setStatusComplete(): void
|
||||
{
|
||||
$this->setStatus('complete');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MediaJon status to invalid.
|
||||
*
|
||||
* @param string $text The status text.
|
||||
* @return void
|
||||
*/
|
||||
public function setStatusInvalid(string $text = ''): void
|
||||
{
|
||||
$this->setStatus('invalid', $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set MediaJob status details.
|
||||
*
|
||||
* @param string $status The status string.
|
||||
* @param string $text The status text.
|
||||
* @param integer $progress The status progress value.
|
||||
* @param integer $progress_max The status progress maximum value.
|
||||
* @return void
|
||||
*/
|
||||
protected function setStatus(string $status, string $text = '', int $progress = 0, int $progress_max = 0): void
|
||||
{
|
||||
$this->status = $status;
|
||||
$this->status_text = $text;
|
||||
$this->progress = $progress;
|
||||
$this->progress_max = $progress_max;
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the MediaJob.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process(): void
|
||||
{
|
||||
$data = json_decode($this->data, true);
|
||||
if ($data !== null) {
|
||||
if (array_key_exists('chunks', $data) === true) {
|
||||
if (array_key_exists('chunk_count', $data) === false) {
|
||||
$this->setStatusInvalid('chunk_count is missing');
|
||||
return;
|
||||
}
|
||||
|
||||
if (array_key_exists('name', $data) === false) {
|
||||
$this->setStatusInvalid('name is missing');
|
||||
return;
|
||||
}
|
||||
|
||||
$numChunks = count($data['chunks']);
|
||||
$maxChunks = intval($data['chunk_count']);
|
||||
if ($numChunks >= $maxChunks) {
|
||||
// merge file and dispatch
|
||||
$this->setStatusProcessing(0, $maxChunks, 'combining chunks');
|
||||
|
||||
$newFile = generateTempFilePath(pathinfo($data['name'], PATHINFO_EXTENSION));
|
||||
$failed = false;
|
||||
|
||||
for ($index = 1; $index <= $maxChunks; $index++) {
|
||||
if (array_key_exists($index, $data['chunks']) === false) {
|
||||
$failed = `{$index} chunk is missing`;
|
||||
} else {
|
||||
$tempFileName = $data['chunks'][$index];
|
||||
|
||||
if ($failed === false) {
|
||||
$chunkContents = file_get_contents($tempFileName);
|
||||
if ($chunkContents === false) {
|
||||
$failed = `{$index} chunk is empty`;
|
||||
} else {
|
||||
file_put_contents($newFile, $chunkContents, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
|
||||
unlink($tempFileName);
|
||||
$this->setStatusProcessing($index, $maxChunks);
|
||||
}
|
||||
}
|
||||
|
||||
unset($data['chunks']);
|
||||
$this->data = json_encode($data);
|
||||
|
||||
if ($failed !== false) {
|
||||
$this->setStatusInvalid($failed);
|
||||
} else {
|
||||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||
$mime = finfo_file($finfo, $newFile);
|
||||
finfo_close($finfo);
|
||||
|
||||
$data['file'] = $newFile;
|
||||
$data['size'] = filesize($newFile);
|
||||
$data['mime_type'] = $mime;
|
||||
|
||||
if (
|
||||
array_key_exists('storage', $data) === true &&
|
||||
array_key_exists('security_type', $data) === true &&
|
||||
array_key_exists('mime_type', $data) === true &&
|
||||
$data['mime_type'] !== ""
|
||||
) {
|
||||
$error = Media::verifyStorage($data['mime_type'], $data['security_type'], $data['storage']);
|
||||
switch ($error) {
|
||||
case Media::STORAGE_VALID:
|
||||
break;
|
||||
case Media::STORAGE_MIME_MISSING:
|
||||
$this->setStatusInvalid('The file type cannot be determined.');
|
||||
return;
|
||||
case Media::STORAGE_NOT_FOUND:
|
||||
$this->setStatusInvalid('Storage was not found.');
|
||||
return;
|
||||
case Media::STORAGE_INVALID_SECURITY:
|
||||
$this->setStatusInvalid('Storage invalid for security value.');
|
||||
return;
|
||||
default:
|
||||
$this->setStatusInvalid('Storage verification error occurred.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->data = json_encode($data);
|
||||
$this->setStatusQueued();
|
||||
MediaWorkerJob::dispatch($this)->onQueue('media');
|
||||
}//end if
|
||||
}//end if
|
||||
} else {
|
||||
$this->setStatusQueued();
|
||||
MediaWorkerJob::dispatch($this)->onQueue('media');
|
||||
}//end if
|
||||
}//end if
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the job owner
|
||||
*
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the media item
|
||||
*
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function media(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Media::class);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Uuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Permission extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Uuids;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'permission',
|
||||
'user',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Get the User associated with this model
|
||||
*
|
||||
* @return Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enum\HttpResponseCodes;
|
||||
use App\Jobs\OptimizeMediaJob;
|
||||
use App\Traits\Uuids;
|
||||
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use InvalidArgumentException;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
|
||||
class Shortlink extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'code',
|
||||
'url',
|
||||
];
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Uuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Subscription extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Uuids;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'email',
|
||||
];
|
||||
}
|
||||
@@ -3,25 +3,14 @@
|
||||
namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
|
||||
use App\Traits\Uuids;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
use OwenIt\Auditing\Contracts\Auditable;
|
||||
|
||||
class User extends Authenticatable implements Auditable
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasApiTokens;
|
||||
use HasFactory;
|
||||
use Notifiable;
|
||||
use Uuids;
|
||||
use \OwenIt\Auditing\Auditable;
|
||||
use HasApiTokens, HasFactory, Notifiable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
@@ -29,12 +18,9 @@ class User extends Authenticatable implements Auditable
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'first_name',
|
||||
'last_name',
|
||||
'name',
|
||||
'email',
|
||||
'phone',
|
||||
'password',
|
||||
'display_name',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -45,7 +31,6 @@ class User extends Authenticatable implements Auditable
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'remember_token',
|
||||
'permissions'
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -55,192 +40,6 @@ class User extends Authenticatable implements Auditable
|
||||
*/
|
||||
protected $casts = [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
];
|
||||
|
||||
// protected $hidden = [
|
||||
// 'permissions'
|
||||
// ];
|
||||
|
||||
/**
|
||||
* The attributes to append.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $appends = [
|
||||
'permissions'
|
||||
];
|
||||
|
||||
/**
|
||||
* The default attributes.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $attributes = [
|
||||
'phone' => '',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Boot the model.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
$clearCache = function ($user) {
|
||||
Cache::forget(
|
||||
"user:{$user->id}",
|
||||
"user:{$user->id}:permissions"
|
||||
);
|
||||
};
|
||||
|
||||
static::saving($clearCache);
|
||||
static::deleting($clearCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of permissions of the user
|
||||
*
|
||||
* @return Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function permissions(): HasMany
|
||||
{
|
||||
return $this->hasMany(Permission::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the permission attribute
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPermissionsAttribute(): array
|
||||
{
|
||||
$cacheKey = "user:{$this->id}:permissions";
|
||||
return Cache::remember($cacheKey, now()->addDays(28), function () {
|
||||
return $this->permissions()->pluck('permission')->toArray();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the permission attribute
|
||||
*
|
||||
* @param array $newPermissions The new permissions to set to the user.
|
||||
* @return void
|
||||
*/
|
||||
public function setPermissionsAttribute(array $newPermissions): void
|
||||
{
|
||||
$existingPermissions = $this->permissions->pluck('permission')->toArray();
|
||||
|
||||
$this->revokePermission(array_diff($this->permissions, $newPermissions));
|
||||
$this->givePermission(array_diff($newPermissions, $this->permissions));
|
||||
|
||||
$cacheKey = "user:{$this->id}:permissions";
|
||||
Cache::delete($cacheKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if user has permission
|
||||
*
|
||||
* @param string $permission Permission to test.
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasPermission(string $permission): bool
|
||||
{
|
||||
return in_array($permission, $this->permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Give permissions to the user
|
||||
*
|
||||
* @param string|array $permissions The permission(s) to give.
|
||||
* @return Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function givePermission($permissions): Collection
|
||||
{
|
||||
if (is_array($permissions) === false) {
|
||||
$permissions = [$permissions];
|
||||
}
|
||||
|
||||
$newPermissions = array_map(function ($permission) {
|
||||
return ['permission' => $permission];
|
||||
}, array_diff($permissions, $this->permissions));
|
||||
|
||||
$cacheKey = "user:{$this->id}:permissions";
|
||||
Cache::forget($cacheKey);
|
||||
|
||||
return $this->permissions()->createMany($newPermissions);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Revoke permissions from the user
|
||||
*
|
||||
* @param string|array $permissions The permission(s) to revoke.
|
||||
* @return integer
|
||||
*/
|
||||
public function revokePermission($permissions): int
|
||||
{
|
||||
if (is_array($permissions) === false) {
|
||||
$permissions = [$permissions];
|
||||
}
|
||||
|
||||
$cacheKey = "user:{$this->id}:permissions";
|
||||
Cache::forget($cacheKey);
|
||||
|
||||
return $this->permissions()
|
||||
->whereIn('permission', $permissions)
|
||||
->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of files of the user
|
||||
*
|
||||
* @return HasMany
|
||||
*/
|
||||
public function media(): HasMany
|
||||
{
|
||||
return $this->hasMany(Media::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of files of the user
|
||||
*
|
||||
* @return HasMany
|
||||
*/
|
||||
public function articles(): HasMany
|
||||
{
|
||||
return $this->hasMany(Article::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get associated user codes
|
||||
*
|
||||
* @return HasMany
|
||||
*/
|
||||
public function codes(): HasMany
|
||||
{
|
||||
return $this->hasMany(UserCode::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of logins of the user
|
||||
*
|
||||
* @return HasMany
|
||||
*/
|
||||
public function logins(): HasMany
|
||||
{
|
||||
return $this->hasMany(UserLogins::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the events associated with the user.
|
||||
*
|
||||
* @return BelongsToMany
|
||||
*/
|
||||
public function events(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Event::class, 'event_user', 'user_id', 'event_id');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class UserCode extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'action',
|
||||
'user_id',
|
||||
'data',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Boot function from Laravel.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function boot(): void
|
||||
{
|
||||
parent::boot();
|
||||
static::creating(function ($model) {
|
||||
UserCode::clearExpired();
|
||||
|
||||
if (empty($model->{'code'}) === true) {
|
||||
while (true) {
|
||||
$code = random_int(100000, 999999);
|
||||
if (UserCode::where('code', $code)->count() === 0) {
|
||||
$model->{'code'} = $code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate new code
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function regenerate(): void
|
||||
{
|
||||
while (true) {
|
||||
$code = random_int(100000, 999999);
|
||||
if (UserCode::where('code', $code)->count() === 0) {
|
||||
$this->code = $code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear expired user codes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function clearExpired(): void
|
||||
{
|
||||
UserCode::where('updated_at', '<=', now()->subDays(5))->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get associated user
|
||||
*
|
||||
* @return Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Traits\Uuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class UserLogins extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Uuids;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'token',
|
||||
'login',
|
||||
'logout',
|
||||
'ip_address',
|
||||
'user_agent',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Get the file user
|
||||
*
|
||||
* @return Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,12 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
@@ -20,34 +16,9 @@ class AppServiceProvider extends ServiceProvider
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
Request::macro('rename', function ($param, $newParam = null) {
|
||||
if (is_array($param) === false) {
|
||||
if ($newParam === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$param = [$param => $newParam];
|
||||
}
|
||||
|
||||
$paramArray = $this->all();
|
||||
foreach ($param as $oldParam => $newParam) {
|
||||
if (isset($paramArray[$oldParam]) === true) {
|
||||
$paramArray[$newParam] = $paramArray[$oldParam];
|
||||
unset($paramArray[$oldParam]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->replace($paramArray);
|
||||
});
|
||||
|
||||
Storage::macro('public', function ($diskName) {
|
||||
$public = config("filesystems.disks.{$diskName}.public", false);
|
||||
return $public;
|
||||
});
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,11 @@ class AuthServiceProvider extends ServiceProvider
|
||||
* @var array<class-string, class-string>
|
||||
*/
|
||||
protected $policies = [
|
||||
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
|
||||
//
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Register any authentication / authorization services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
|
||||
@@ -9,8 +9,6 @@ class BroadcastServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
|
||||
@@ -5,10 +5,7 @@ namespace App\Providers;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
use Illuminate\Queue\Events\JobProcessed;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -23,11 +20,8 @@ class EventServiceProvider extends ServiceProvider
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Register any events for your application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
@@ -36,8 +30,6 @@ class EventServiceProvider extends ServiceProvider
|
||||
|
||||
/**
|
||||
* Determine if events and listeners should be automatically discovered.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function shouldDiscoverEvents(): bool
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user