Compare commits
9 commits
Author | SHA1 | Date | |
---|---|---|---|
70f90dd456 | |||
cd5c97afd3 | |||
97f3848b66 | |||
540bd17792 | |||
1fe9a42d8d | |||
cf978cd749 | |||
126bb29ae2 | |||
7a58287b34 | |||
328c9badb4 |
188 changed files with 1798 additions and 2130 deletions
|
@ -1,14 +0,0 @@
|
||||||
APP_ENV=testing
|
|
||||||
APP_DEBUG=true
|
|
||||||
APP_KEY=base64:6DJhvZLVjE6dD4Cqrteh+6Z5vZlG+v/soCKcDHLOAH0=
|
|
||||||
APP_URL=http://localhost:8000
|
|
||||||
APP_LONGURL=localhost
|
|
||||||
APP_SHORTURL=local
|
|
||||||
|
|
||||||
DB_CONNECTION=travis
|
|
||||||
|
|
||||||
CACHE_DRIVER=array
|
|
||||||
SESSION_DRIVER=file
|
|
||||||
QUEUE_DRIVER=sync
|
|
||||||
|
|
||||||
SCOUT_DRIVER=pgsql
|
|
|
@ -4,8 +4,6 @@ APP_KEY=
|
||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
APP_TIMEZONE=UTC
|
APP_TIMEZONE=UTC
|
||||||
APP_URL=https://example.com
|
APP_URL=https://example.com
|
||||||
APP_LONGURL=example.com
|
|
||||||
APP_SHORTURL=examp.le
|
|
||||||
|
|
||||||
APP_LOCALE=en
|
APP_LOCALE=en
|
||||||
APP_FALLBACK_LOCALE=en
|
APP_FALLBACK_LOCALE=en
|
||||||
|
|
70
.env.github
70
.env.github
|
@ -1,70 +0,0 @@
|
||||||
APP_NAME=Laravel
|
|
||||||
APP_ENV=testing
|
|
||||||
APP_KEY=SomeRandomString # Leave this
|
|
||||||
APP_DEBUG=false
|
|
||||||
APP_LOG_LEVEL=warning
|
|
||||||
|
|
||||||
DB_CONNECTION=pgsql
|
|
||||||
DB_HOST=127.0.0.1
|
|
||||||
DB_PORT=5432
|
|
||||||
DB_DATABASE=jbukdev_testing
|
|
||||||
DB_USERNAME=postgres
|
|
||||||
DB_PASSWORD=postgres
|
|
||||||
|
|
||||||
BROADCAST_DRIVER=log
|
|
||||||
CACHE_DRIVER=file
|
|
||||||
SESSION_DRIVER=file
|
|
||||||
QUEUE_DRIVER=sync
|
|
||||||
|
|
||||||
REDIS_HOST=127.0.0.1
|
|
||||||
REDIS_PASSWORD=null
|
|
||||||
REDIS_PORT=6379
|
|
||||||
|
|
||||||
MAIL_DRIVER=smtp
|
|
||||||
MAIL_HOST=smtp.mailtrap.io
|
|
||||||
MAIL_PORT=2525
|
|
||||||
MAIL_USERNAME=null
|
|
||||||
MAIL_PASSWORD=null
|
|
||||||
MAIL_ENCRYPTION=null
|
|
||||||
|
|
||||||
PUSHER_APP_ID=
|
|
||||||
PUSHER_APP_KEY=
|
|
||||||
PUSHER_APP_SECRET=
|
|
||||||
|
|
||||||
AWS_S3_KEY=your-key
|
|
||||||
AWS_S3_SECRET=your-secret
|
|
||||||
AWS_S3_REGION=region
|
|
||||||
AWS_S3_BUCKET=your-bucket
|
|
||||||
AWS_S3_URL=https://xxxxxxx.s3-region.amazonaws.com
|
|
||||||
|
|
||||||
APP_URL=https://example.com # This one is necessary
|
|
||||||
APP_LONGURL=example.com
|
|
||||||
APP_SHORTURL=examp.le
|
|
||||||
|
|
||||||
ADMIN_USER=admin # pick something better, this is used for `/admin`
|
|
||||||
ADMIN_PASS=password
|
|
||||||
DISPLAY_NAME="Joe Bloggs" # This is used for example in the header and titles
|
|
||||||
|
|
||||||
TWITTER_CONSUMER_KEY=
|
|
||||||
TWITTER_CONSUMER_SECRET=
|
|
||||||
TWITTER_ACCESS_TOKEN=
|
|
||||||
TWITTER_ACCESS_TOKEN_SECRET=
|
|
||||||
|
|
||||||
SCOUT_DRIVER=database
|
|
||||||
SCOUT_QUEUE=false
|
|
||||||
|
|
||||||
PIWIK=false
|
|
||||||
|
|
||||||
FATHOM_ID=
|
|
||||||
|
|
||||||
APP_TIMEZONE=UTC
|
|
||||||
APP_LANG=en
|
|
||||||
APP_LOG=daily
|
|
||||||
SECURE_SESSION_COOKIE=true
|
|
||||||
|
|
||||||
LOG_SLACK_WEBHOOK_URL=
|
|
||||||
FLARE_KEY=
|
|
||||||
|
|
||||||
FONT_LINK=
|
|
||||||
|
|
||||||
BRIDGY_MASTODON_TOKEN=
|
|
4
.gitattributes
vendored
4
.gitattributes
vendored
|
@ -5,7 +5,3 @@
|
||||||
*.html diff=html
|
*.html diff=html
|
||||||
*.md diff=markdown
|
*.md diff=markdown
|
||||||
*.php diff=php
|
*.php diff=php
|
||||||
|
|
||||||
/.github export-ignore
|
|
||||||
CHANGELOG.md export-ignore
|
|
||||||
.styleci.yml export-ignore
|
|
||||||
|
|
17
.github/dependabot.yml
vendored
17
.github/dependabot.yml
vendored
|
@ -1,17 +0,0 @@
|
||||||
version: 2
|
|
||||||
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "composer"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
|
|
||||||
- package-ecosystem: "npm"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
144
.github/workflows/deploy.yml
vendored
144
.github/workflows/deploy.yml
vendored
|
@ -1,144 +0,0 @@
|
||||||
name: Deploy
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
deploy:
|
|
||||||
name: Deploy
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
environment: Hetzner
|
|
||||||
env:
|
|
||||||
repository: 'jonnybarnes/jonnybarnes.uk'
|
|
||||||
newReleaseName: '${{ github.run_id }}'
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: 🌍 Set Environment Variables
|
|
||||||
run: |
|
|
||||||
echo "releasesDir=${{ secrets.DEPLOYMENT_BASE_DIR }}/releases" >> $GITHUB_ENV
|
|
||||||
echo "persistentDir=${{ secrets.DEPLOYMENT_BASE_DIR }}/persistent" >> $GITHUB_ENV
|
|
||||||
echo "currentDir=${{ secrets.DEPLOYMENT_BASE_DIR }}/current" >> $GITHUB_ENV
|
|
||||||
- name: 🌎 Set Environment Variables Part 2
|
|
||||||
run: |
|
|
||||||
echo "newReleaseDir=${{ env.releasesDir }}/${{ env.newReleaseName }}" >> $GITHUB_ENV
|
|
||||||
- name: 🔄 Clone Repository
|
|
||||||
uses: appleboy/ssh-action@master
|
|
||||||
with:
|
|
||||||
host: ${{ secrets.DEPLOYMENT_HOST }}
|
|
||||||
port: ${{ secrets.DEPLOYMENT_PORT }}
|
|
||||||
username: ${{ secrets.DEPLOYMENT_USER }}
|
|
||||||
key: ${{ secrets.DEPLOYMENT_KEY }}
|
|
||||||
script: |
|
|
||||||
[ -d ${{ env.releasesDir }} ] || mkdir ${{ env.releasesDir }}
|
|
||||||
[ -d ${{ env.persistentDir }} ] || mkdir ${{ env.persistentDir }}
|
|
||||||
[ -d ${{ env.persistentDir }}/storage ] || mkdir ${{ env.persistentDir }}/storage
|
|
||||||
|
|
||||||
cd ${{ env.releasesDir }}
|
|
||||||
|
|
||||||
# Create new release directory
|
|
||||||
mkdir ${{ env.newReleaseDir }}
|
|
||||||
|
|
||||||
# Clone app
|
|
||||||
git clone --depth 1 --branch ${{ github.ref_name }} https://github.com/${{ env.repository }} ${{ env.newReleaseName }}
|
|
||||||
|
|
||||||
# Mark release
|
|
||||||
cd ${{ env.newReleaseDir }}
|
|
||||||
echo "${{ env.newReleaseName }}" > public/release-name.txt
|
|
||||||
|
|
||||||
# Fix cache directory permissions
|
|
||||||
sudo chown -R ${{ secrets.HTTP_USER }}:${{ secrets.HTTP_USER }} bootstrap/cache
|
|
||||||
|
|
||||||
- name: 🎵 Run Composer
|
|
||||||
uses: appleboy/ssh-action@master
|
|
||||||
with:
|
|
||||||
host: ${{ secrets.DEPLOYMENT_HOST }}
|
|
||||||
port: ${{ secrets.DEPLOYMENT_PORT }}
|
|
||||||
username: ${{ secrets.DEPLOYMENT_USER }}
|
|
||||||
key: ${{ secrets.DEPLOYMENT_KEY }}
|
|
||||||
script: |
|
|
||||||
cd ${{ env.newReleaseDir }}
|
|
||||||
composer install --prefer-dist --no-scripts --no-dev --no-progress --optimize-autoloader --quiet --no-interaction
|
|
||||||
|
|
||||||
- name: 🔗 Update Symlinks
|
|
||||||
uses: appleboy/ssh-action@master
|
|
||||||
with:
|
|
||||||
host: ${{ secrets.DEPLOYMENT_HOST }}
|
|
||||||
port: ${{ secrets.DEPLOYMENT_PORT }}
|
|
||||||
username: ${{ secrets.DEPLOYMENT_USER }}
|
|
||||||
key: ${{ secrets.DEPLOYMENT_KEY }}
|
|
||||||
script: |
|
|
||||||
# Import the environment config
|
|
||||||
cd ${{ env.newReleaseDir }};
|
|
||||||
ln -nfs ${{ secrets.DEPLOYMENT_BASE_DIR }}/.env .env;
|
|
||||||
|
|
||||||
# Remove the storage directory and replace with persistent data
|
|
||||||
rm -rf ${{ env.newReleaseDir }}/storage;
|
|
||||||
cd ${{ env.newReleaseDir }};
|
|
||||||
ln -nfs ${{ secrets.DEPLOYMENT_BASE_DIR }}/persistent/storage storage;
|
|
||||||
|
|
||||||
# Remove the public/profile-images directory and replace with persistent data
|
|
||||||
rm -rf ${{ env.newReleaseDir }}/public/assets/profile-images;
|
|
||||||
cd ${{ env.newReleaseDir }};
|
|
||||||
ln -nfs ${{ secrets.DEPLOYMENT_BASE_DIR }}/persistent/profile-images public/assets/profile-images;
|
|
||||||
|
|
||||||
# Add the persistent files data
|
|
||||||
cd ${{ env.newReleaseDir }};
|
|
||||||
ln -nfs ${{ secrets.DEPLOYMENT_BASE_DIR }}/persistent/files public/files;
|
|
||||||
|
|
||||||
# Add the persistent fonts data
|
|
||||||
cd ${{ env.newReleaseDir }};
|
|
||||||
ln -nfs ${{ secrets.DEPLOYMENT_BASE_DIR }}/persistent/fonts public/fonts;
|
|
||||||
|
|
||||||
- name: ✨ Optimize Installation
|
|
||||||
uses: appleboy/ssh-action@master
|
|
||||||
with:
|
|
||||||
host: ${{ secrets.DEPLOYMENT_HOST }}
|
|
||||||
port: ${{ secrets.DEPLOYMENT_PORT }}
|
|
||||||
username: ${{ secrets.DEPLOYMENT_USER }}
|
|
||||||
key: ${{ secrets.DEPLOYMENT_KEY }}
|
|
||||||
script: |
|
|
||||||
cd ${{ env.newReleaseDir }};
|
|
||||||
sudo runuser -u ${{ secrets.HTTP_USER }} -- php artisan clear-compiled;
|
|
||||||
|
|
||||||
- name: 🙈 Migrate database
|
|
||||||
uses: appleboy/ssh-action@master
|
|
||||||
with:
|
|
||||||
host: ${{ secrets.DEPLOYMENT_HOST }}
|
|
||||||
port: ${{ secrets.DEPLOYMENT_PORT }}
|
|
||||||
username: ${{ secrets.DEPLOYMENT_USER }}
|
|
||||||
key: ${{ secrets.DEPLOYMENT_KEY }}
|
|
||||||
script: |
|
|
||||||
cd ${{ env.newReleaseDir }}
|
|
||||||
sudo runuser -u ${{ secrets.HTTP_USER }} -- php artisan migrate --force
|
|
||||||
|
|
||||||
- name: 🙏 Bless release
|
|
||||||
uses: appleboy/ssh-action@master
|
|
||||||
with:
|
|
||||||
host: ${{ secrets.DEPLOYMENT_HOST }}
|
|
||||||
port: ${{ secrets.DEPLOYMENT_PORT }}
|
|
||||||
username: ${{ secrets.DEPLOYMENT_USER }}
|
|
||||||
key: ${{ secrets.DEPLOYMENT_KEY }}
|
|
||||||
script: |
|
|
||||||
ln -nfs ${{ env.newReleaseDir }} ${{ env.currentDir }};
|
|
||||||
cd ${{ env.newReleaseDir }}
|
|
||||||
sudo runuser -u ${{ secrets.HTTP_USER }} -- php artisan horizon:terminate
|
|
||||||
sudo runuser -u ${{ secrets.HTTP_USER }} -- php artisan config:cache
|
|
||||||
sudo runuser -u ${{ secrets.HTTP_USER }} -- php artisan event:cache
|
|
||||||
sudo runuser -u ${{ secrets.HTTP_USER }} -- php artisan route:cache
|
|
||||||
sudo runuser -u ${{ secrets.HTTP_USER }} -- php artisan view:cache
|
|
||||||
|
|
||||||
sudo systemctl restart php-fpm.service
|
|
||||||
sudo systemctl restart jbuk-horizon.service
|
|
||||||
|
|
||||||
- name: 🚾 Clean up old releases
|
|
||||||
uses: appleboy/ssh-action@master
|
|
||||||
with:
|
|
||||||
host: ${{ secrets.DEPLOYMENT_HOST }}
|
|
||||||
port: ${{ secrets.DEPLOYMENT_PORT }}
|
|
||||||
username: ${{ secrets.DEPLOYMENT_USER }}
|
|
||||||
key: ${{ secrets.DEPLOYMENT_KEY }}
|
|
||||||
script: |
|
|
||||||
fd '.+' ${{ env.releasesDir }} -d 1 | head -n -3 | xargs -d "\n" -I'{}' sudo chown -R ${{ secrets.DEPLOYMENT_USER }}:${{ secrets.DEPLOYMENT_USER }} {}
|
|
||||||
fd '.+' ${{ env.releasesDir }} -d 1 | head -n -3 | xargs -d "\n" -I'{}' rm -rf {}
|
|
65
.github/workflows/phpunit.yml
vendored
65
.github/workflows/phpunit.yml
vendored
|
@ -1,65 +0,0 @@
|
||||||
name: PHP Unit
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
phpunit:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
name: PHPUnit test suite
|
|
||||||
|
|
||||||
services:
|
|
||||||
postgres:
|
|
||||||
image: postgres:latest
|
|
||||||
env:
|
|
||||||
POSTGRES_USER: postgres
|
|
||||||
POSTGRES_PASSWORD: postgres
|
|
||||||
POSTGRES_DB: jbukdev_testing
|
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup PHP
|
|
||||||
uses: shivammathur/setup-php@v2
|
|
||||||
with:
|
|
||||||
php-version: '8.3'
|
|
||||||
extensions: mbstring, intl, phpredis, imagick
|
|
||||||
coverage: xdebug
|
|
||||||
tools: phpunit
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Copy .env
|
|
||||||
run: php -r "file_exists('.env') || copy('.env.github', '.env');"
|
|
||||||
|
|
||||||
- name: Get Composer Cache Directory
|
|
||||||
id: composer-cache
|
|
||||||
run: |
|
|
||||||
echo "::set-output name=dir::$(composer config cache-files-dir)"
|
|
||||||
|
|
||||||
- name: Cache composer dependencies
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ${{ steps.composer-cache.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-php-8.3-composer-${{ hashFiles('**/composer.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-php-8.3-composer-
|
|
||||||
|
|
||||||
- name: Install Composer Dependencies
|
|
||||||
run: composer install --quiet --no-ansi --no-interaction --no-progress
|
|
||||||
|
|
||||||
- name: Generate Key
|
|
||||||
run: php artisan key:generate
|
|
||||||
|
|
||||||
- name: Setup Directory Permissions
|
|
||||||
run: chmod -R 777 storage bootstrap/cache
|
|
||||||
|
|
||||||
- name: Setup Database
|
|
||||||
run: php artisan migrate
|
|
||||||
|
|
||||||
- name: Execute PHPUnit Tests
|
|
||||||
run: vendor/bin/phpunit
|
|
38
.github/workflows/pint.yml
vendored
38
.github/workflows/pint.yml
vendored
|
@ -1,38 +0,0 @@
|
||||||
name: Laravel Pint
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
pint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
name: Laravel Pint
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup PHP with pecl extensions
|
|
||||||
uses: shivammathur/setup-php@v2
|
|
||||||
with:
|
|
||||||
php-version: '8.2'
|
|
||||||
|
|
||||||
- name: Get Composer Cache Directory
|
|
||||||
id: composer-cache
|
|
||||||
run: |
|
|
||||||
echo "::set-output name=dir::$(composer config cache-files-dir)"
|
|
||||||
|
|
||||||
- name: Cache composer dependencies
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ${{ steps.composer-cache.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-composer-
|
|
||||||
|
|
||||||
- name: Install Composer Dependencies
|
|
||||||
run: composer install --quiet --no-ansi --no-interaction --no-progress
|
|
||||||
|
|
||||||
- name: Check Files with Laravel Pint
|
|
||||||
run: vendor/bin/pint --test
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,7 +4,6 @@
|
||||||
/public/coverage
|
/public/coverage
|
||||||
/public/hot
|
/public/hot
|
||||||
/public/files
|
/public/files
|
||||||
/public/fonts
|
|
||||||
/public/storage
|
/public/storage
|
||||||
/storage/*.key
|
/storage/*.key
|
||||||
/vendor
|
/vendor
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "/Users/jonny/git/phpactor/phpactor.schema.json",
|
|
||||||
"language_server_phpstan.enabled": false,
|
|
||||||
"language_server_psalm.enabled": true
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
php:
|
|
||||||
preset: laravel
|
|
||||||
disabled:
|
|
||||||
- no_unused_imports
|
|
||||||
finder:
|
|
||||||
not-name:
|
|
||||||
- index.php
|
|
||||||
js: true
|
|
||||||
css: true
|
|
|
@ -8,8 +8,6 @@ use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @codeCoverageIgnore
|
* @codeCoverageIgnore
|
||||||
*
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
*/
|
||||||
class MigratePlaceDataFromPostgis extends Command
|
class MigratePlaceDataFromPostgis extends Command
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,9 +9,6 @@ use Illuminate\Console\Command;
|
||||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||||
use Illuminate\FileSystem\FileSystem;
|
use Illuminate\FileSystem\FileSystem;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class ParseCachedWebMentions extends Command
|
class ParseCachedWebMentions extends Command
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,9 +8,6 @@ use App\Jobs\DownloadWebMention;
|
||||||
use App\Models\WebMention;
|
use App\Models\WebMention;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class ReDownloadWebMentions extends Command
|
class ReDownloadWebMentions extends Command
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,9 +9,6 @@ use App\Models\Article;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class ArticlesController extends Controller
|
class ArticlesController extends Controller
|
||||||
{
|
{
|
||||||
public function index(): View
|
public function index(): View
|
||||||
|
|
|
@ -10,9 +10,6 @@ use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class BioController extends Controller
|
class BioController extends Controller
|
||||||
{
|
{
|
||||||
public function show(): View
|
public function show(): View
|
||||||
|
|
|
@ -9,9 +9,6 @@ use App\Models\MicropubClient;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class ClientsController extends Controller
|
class ClientsController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -12,9 +12,6 @@ use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class ContactsController extends Controller
|
class ContactsController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,9 +7,6 @@ namespace App\Http\Controllers\Admin;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class HomeController extends Controller
|
class HomeController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,9 +10,6 @@ use App\Models\Like;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class LikesController extends Controller
|
class LikesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,9 +11,6 @@ use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class NotesController extends Controller
|
class NotesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,6 +18,7 @@ use Illuminate\Support\Facades\App;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
use ParagonIE\ConstantTime\Base64UrlSafe;
|
use ParagonIE\ConstantTime\Base64UrlSafe;
|
||||||
|
use Random\RandomException;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
use Webauthn\AttestationStatement\AttestationStatementSupportManager;
|
use Webauthn\AttestationStatement\AttestationStatementSupportManager;
|
||||||
use Webauthn\AttestationStatement\NoneAttestationStatementSupport;
|
use Webauthn\AttestationStatement\NoneAttestationStatementSupport;
|
||||||
|
@ -38,9 +39,6 @@ use Webauthn\PublicKeyCredentialRpEntity;
|
||||||
use Webauthn\PublicKeyCredentialSource;
|
use Webauthn\PublicKeyCredentialSource;
|
||||||
use Webauthn\PublicKeyCredentialUserEntity;
|
use Webauthn\PublicKeyCredentialUserEntity;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class PasskeysController extends Controller
|
class PasskeysController extends Controller
|
||||||
{
|
{
|
||||||
public function index(): View
|
public function index(): View
|
||||||
|
@ -52,22 +50,26 @@ class PasskeysController extends Controller
|
||||||
return view('admin.passkeys.index', compact('passkeys'));
|
return view('admin.passkeys.index', compact('passkeys'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCreateOptions(): JsonResponse
|
/**
|
||||||
|
* @throws RandomException
|
||||||
|
* @throws \JsonException
|
||||||
|
*/
|
||||||
|
public function getCreateOptions(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
// RP Entity i.e. the application
|
// RP Entity i.e. the application
|
||||||
$rpEntity = PublicKeyCredentialRpEntity::create(
|
$rpEntity = PublicKeyCredentialRpEntity::create(
|
||||||
config('app.name'),
|
name: config('app.name'),
|
||||||
config('url.longurl'),
|
id: config('app.url'),
|
||||||
);
|
);
|
||||||
|
|
||||||
// User Entity
|
// User Entity
|
||||||
$userEntity = PublicKeyCredentialUserEntity::create(
|
$userEntity = PublicKeyCredentialUserEntity::create(
|
||||||
$user->name,
|
name: $user->name,
|
||||||
(string) $user->id,
|
id: (string) $user->id,
|
||||||
$user->name,
|
displayName: $user->name,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Challenge
|
// Challenge
|
||||||
|
@ -85,25 +87,38 @@ class PasskeysController extends Controller
|
||||||
$authenticatorSelectionCriteria = AuthenticatorSelectionCriteria::create(
|
$authenticatorSelectionCriteria = AuthenticatorSelectionCriteria::create(
|
||||||
userVerification: AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_REQUIRED,
|
userVerification: AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_REQUIRED,
|
||||||
residentKey: AuthenticatorSelectionCriteria::RESIDENT_KEY_REQUIREMENT_REQUIRED,
|
residentKey: AuthenticatorSelectionCriteria::RESIDENT_KEY_REQUIREMENT_REQUIRED,
|
||||||
requireResidentKey: true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$options = PublicKeyCredentialCreationOptions::create(
|
$publicKeyCredentialCreationOptions = PublicKeyCredentialCreationOptions::create(
|
||||||
$rpEntity,
|
rp: $rpEntity,
|
||||||
$userEntity,
|
user: $userEntity,
|
||||||
$challenge,
|
challenge: $challenge,
|
||||||
$pubKeyCredParams,
|
pubKeyCredParams: $pubKeyCredParams,
|
||||||
authenticatorSelection: $authenticatorSelectionCriteria,
|
authenticatorSelection: $authenticatorSelectionCriteria,
|
||||||
attestation: PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE
|
attestation: PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE
|
||||||
);
|
);
|
||||||
|
|
||||||
$options = json_encode($options, JSON_THROW_ON_ERROR);
|
$attestationStatementSupportManager = new AttestationStatementSupportManager;
|
||||||
|
$attestationStatementSupportManager->add(new NoneAttestationStatementSupport);
|
||||||
|
$webauthnSerializerFactory = new WebauthnSerializerFactory(
|
||||||
|
attestationStatementSupportManager: $attestationStatementSupportManager
|
||||||
|
);
|
||||||
|
$webauthnSerializer = $webauthnSerializerFactory->create();
|
||||||
|
$publicKeyCredentialCreationOptions = $webauthnSerializer->serialize(
|
||||||
|
data: $publicKeyCredentialCreationOptions,
|
||||||
|
format: 'json'
|
||||||
|
);
|
||||||
|
|
||||||
session(['create_options' => $options]);
|
$request->session()->put('create_options', $publicKeyCredentialCreationOptions);
|
||||||
|
|
||||||
return JsonResponse::fromJsonString($options);
|
return JsonResponse::fromJsonString($publicKeyCredentialCreationOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws Throwable
|
||||||
|
* @throws WebauthnException
|
||||||
|
* @throws \JsonException
|
||||||
|
*/
|
||||||
public function create(Request $request): JsonResponse
|
public function create(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
|
@ -111,17 +126,17 @@ class PasskeysController extends Controller
|
||||||
|
|
||||||
$publicKeyCredentialCreationOptionsData = session('create_options');
|
$publicKeyCredentialCreationOptionsData = session('create_options');
|
||||||
// Unset session data to mitigate replay attacks
|
// Unset session data to mitigate replay attacks
|
||||||
session()->forget('create_options');
|
$request->session()->forget('create_options');
|
||||||
if (empty($publicKeyCredentialCreationOptionsData)) {
|
if (empty($publicKeyCredentialCreationOptionsData)) {
|
||||||
throw new WebAuthnException('No public key credential request options found');
|
throw new WebAuthnException('No public key credential request options found');
|
||||||
}
|
}
|
||||||
|
|
||||||
$attestationStatementSupportManager = new AttestationStatementSupportManager;
|
$attestationStatementSupportManager = new AttestationStatementSupportManager;
|
||||||
$attestationStatementSupportManager->add(new NoneAttestationStatementSupport);
|
$attestationStatementSupportManager->add(new NoneAttestationStatementSupport);
|
||||||
|
$webauthnSerializerFactory = new WebauthnSerializerFactory(
|
||||||
$webauthnSerializer = (new WebauthnSerializerFactory(
|
attestationStatementSupportManager: $attestationStatementSupportManager
|
||||||
$attestationStatementSupportManager
|
);
|
||||||
))->create();
|
$webauthnSerializer = $webauthnSerializerFactory->create();
|
||||||
|
|
||||||
$publicKeyCredential = $webauthnSerializer->deserialize(
|
$publicKeyCredential = $webauthnSerializer->deserialize(
|
||||||
json_encode($request->all(), JSON_THROW_ON_ERROR),
|
json_encode($request->all(), JSON_THROW_ON_ERROR),
|
||||||
|
@ -146,11 +161,11 @@ class PasskeysController extends Controller
|
||||||
$ceremonyStepManagerFactory->setExtensionOutputCheckerHandler(
|
$ceremonyStepManagerFactory->setExtensionOutputCheckerHandler(
|
||||||
ExtensionOutputCheckerHandler::create()
|
ExtensionOutputCheckerHandler::create()
|
||||||
);
|
);
|
||||||
$securedRelyingPartyId = [];
|
$allowedOrigins = [];
|
||||||
if (App::environment('local', 'development')) {
|
if (App::environment('local', 'development')) {
|
||||||
$securedRelyingPartyId = [config('url.longurl')];
|
$allowedOrigins = [config('app.url')];
|
||||||
}
|
}
|
||||||
$ceremonyStepManagerFactory->setSecuredRelyingPartyId($securedRelyingPartyId);
|
$ceremonyStepManagerFactory->setAllowedOrigins($allowedOrigins);
|
||||||
|
|
||||||
$authenticatorAttestationResponseValidator = AuthenticatorAttestationResponseValidator::create(
|
$authenticatorAttestationResponseValidator = AuthenticatorAttestationResponseValidator::create(
|
||||||
ceremonyStepManager: $ceremonyStepManagerFactory->creationCeremony()
|
ceremonyStepManager: $ceremonyStepManagerFactory->creationCeremony()
|
||||||
|
@ -165,8 +180,7 @@ class PasskeysController extends Controller
|
||||||
$publicKeyCredentialSource = $authenticatorAttestationResponseValidator->check(
|
$publicKeyCredentialSource = $authenticatorAttestationResponseValidator->check(
|
||||||
authenticatorAttestationResponse: $publicKeyCredential->response,
|
authenticatorAttestationResponse: $publicKeyCredential->response,
|
||||||
publicKeyCredentialCreationOptions: $publicKeyCredentialCreationOptions,
|
publicKeyCredentialCreationOptions: $publicKeyCredentialCreationOptions,
|
||||||
request: config('url.longurl'),
|
host: config('app.url')
|
||||||
securedRelyingPartyId: $securedRelyingPartyId,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$user->passkey()->create([
|
$user->passkey()->create([
|
||||||
|
@ -180,24 +194,37 @@ class PasskeysController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRequestOptions(): JsonResponse
|
/**
|
||||||
|
* @throws RandomException
|
||||||
|
* @throws \JsonException
|
||||||
|
*/
|
||||||
|
public function getRequestOptions(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions::create(
|
$publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions::create(
|
||||||
challenge: random_bytes(16),
|
challenge: random_bytes(16),
|
||||||
userVerification: PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_REQUIRED
|
userVerification: PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_REQUIRED
|
||||||
);
|
);
|
||||||
|
|
||||||
$publicKeyCredentialRequestOptions = json_encode($publicKeyCredentialRequestOptions, JSON_THROW_ON_ERROR);
|
$attestationStatementSupportManager = AttestationStatementSupportManager::create();
|
||||||
|
$attestationStatementSupportManager->add(NoneAttestationStatementSupport::create());
|
||||||
|
$factory = new WebauthnSerializerFactory(
|
||||||
|
attestationStatementSupportManager: $attestationStatementSupportManager
|
||||||
|
);
|
||||||
|
$serializer = $factory->create();
|
||||||
|
$publicKeyCredentialRequestOptions = $serializer->serialize(data: $publicKeyCredentialRequestOptions, format: 'json');
|
||||||
|
|
||||||
session(['request_options' => $publicKeyCredentialRequestOptions]);
|
$request->session()->put('request_options', $publicKeyCredentialRequestOptions);
|
||||||
|
|
||||||
return JsonResponse::fromJsonString($publicKeyCredentialRequestOptions);
|
return JsonResponse::fromJsonString($publicKeyCredentialRequestOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \JsonException
|
||||||
|
*/
|
||||||
public function login(Request $request): JsonResponse
|
public function login(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$requestOptions = session('request_options');
|
$requestOptions = session('request_options');
|
||||||
session()->forget('request_options');
|
$request->session()->forget('request_options');
|
||||||
|
|
||||||
if (empty($requestOptions)) {
|
if (empty($requestOptions)) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
|
@ -209,9 +236,10 @@ class PasskeysController extends Controller
|
||||||
$attestationStatementSupportManager = new AttestationStatementSupportManager;
|
$attestationStatementSupportManager = new AttestationStatementSupportManager;
|
||||||
$attestationStatementSupportManager->add(new NoneAttestationStatementSupport);
|
$attestationStatementSupportManager->add(new NoneAttestationStatementSupport);
|
||||||
|
|
||||||
$webauthnSerializer = (new WebauthnSerializerFactory(
|
$webauthnSerializerFactory = new WebauthnSerializerFactory(
|
||||||
$attestationStatementSupportManager
|
attestationStatementSupportManager: $attestationStatementSupportManager
|
||||||
))->create();
|
);
|
||||||
|
$webauthnSerializer = $webauthnSerializerFactory->create();
|
||||||
|
|
||||||
$publicKeyCredential = $webauthnSerializer->deserialize(
|
$publicKeyCredential = $webauthnSerializer->deserialize(
|
||||||
json_encode($request->all(), JSON_THROW_ON_ERROR),
|
json_encode($request->all(), JSON_THROW_ON_ERROR),
|
||||||
|
@ -256,11 +284,11 @@ class PasskeysController extends Controller
|
||||||
$ceremonyStepManagerFactory->setExtensionOutputCheckerHandler(
|
$ceremonyStepManagerFactory->setExtensionOutputCheckerHandler(
|
||||||
ExtensionOutputCheckerHandler::create()
|
ExtensionOutputCheckerHandler::create()
|
||||||
);
|
);
|
||||||
$securedRelyingPartyId = [];
|
$allowedOrigins = [];
|
||||||
if (App::environment('local', 'development')) {
|
if (App::environment('local', 'development')) {
|
||||||
$securedRelyingPartyId = [config('url.longurl')];
|
$allowedOrigins = [config('app.url')];
|
||||||
}
|
}
|
||||||
$ceremonyStepManagerFactory->setSecuredRelyingPartyId($securedRelyingPartyId);
|
$ceremonyStepManagerFactory->setAllowedOrigins($allowedOrigins);
|
||||||
|
|
||||||
$authenticatorAssertionResponseValidator = AuthenticatorAssertionResponseValidator::create(
|
$authenticatorAssertionResponseValidator = AuthenticatorAssertionResponseValidator::create(
|
||||||
ceremonyStepManager: $ceremonyStepManagerFactory->requestCeremony()
|
ceremonyStepManager: $ceremonyStepManagerFactory->requestCeremony()
|
||||||
|
@ -274,12 +302,11 @@ class PasskeysController extends Controller
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$authenticatorAssertionResponseValidator->check(
|
$authenticatorAssertionResponseValidator->check(
|
||||||
credentialId: $publicKeyCredentialSource,
|
publicKeyCredentialSource: $publicKeyCredentialSource,
|
||||||
authenticatorAssertionResponse: $publicKeyCredential->response,
|
authenticatorAssertionResponse: $publicKeyCredential->response,
|
||||||
publicKeyCredentialRequestOptions: $publicKeyCredentialRequestOptions,
|
publicKeyCredentialRequestOptions: $publicKeyCredentialRequestOptions,
|
||||||
request: config('url.longurl'),
|
host: config('app.url'),
|
||||||
userHandle: null,
|
userHandle: null,
|
||||||
securedRelyingPartyId: $securedRelyingPartyId,
|
|
||||||
);
|
);
|
||||||
} catch (Throwable) {
|
} catch (Throwable) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
|
|
|
@ -10,9 +10,6 @@ use App\Services\PlaceService;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class PlacesController extends Controller
|
class PlacesController extends Controller
|
||||||
{
|
{
|
||||||
protected PlaceService $placeService;
|
protected PlaceService $placeService;
|
||||||
|
|
|
@ -10,9 +10,6 @@ use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class SyndicationTargetsController extends Controller
|
class SyndicationTargetsController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,9 +10,6 @@ use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
use Jonnybarnes\IndieWeb\Numbers;
|
use Jonnybarnes\IndieWeb\Numbers;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class ArticlesController extends Controller
|
class ArticlesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,9 +9,6 @@ use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class AuthController extends Controller
|
class AuthController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,9 +7,6 @@ namespace App\Http\Controllers;
|
||||||
use App\Models\Bookmark;
|
use App\Models\Bookmark;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class BookmarksController extends Controller
|
class BookmarksController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,9 +8,6 @@ use App\Models\Contact;
|
||||||
use Illuminate\Filesystem\Filesystem;
|
use Illuminate\Filesystem\Filesystem;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class ContactsController extends Controller
|
class ContactsController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,9 +9,6 @@ use App\Models\Note;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class FeedsController extends Controller
|
class FeedsController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -122,8 +119,8 @@ class FeedsController extends Controller
|
||||||
|
|
||||||
foreach ($notes as $key => $note) {
|
foreach ($notes as $key => $note) {
|
||||||
$data['items'][$key] = [
|
$data['items'][$key] = [
|
||||||
'id' => $note->longurl,
|
'id' => $note->uri,
|
||||||
'url' => $note->longurl,
|
'url' => $note->uri,
|
||||||
'content_text' => $note->content,
|
'content_text' => $note->content,
|
||||||
'date_published' => $note->created_at->tz('UTC')->toRfc3339String(),
|
'date_published' => $note->created_at->tz('UTC')->toRfc3339String(),
|
||||||
'date_modified' => $note->updated_at->tz('UTC')->toRfc3339String(),
|
'date_modified' => $note->updated_at->tz('UTC')->toRfc3339String(),
|
||||||
|
@ -164,7 +161,7 @@ class FeedsController extends Controller
|
||||||
'author' => [
|
'author' => [
|
||||||
'type' => 'card',
|
'type' => 'card',
|
||||||
'name' => config('user.display_name'),
|
'name' => config('user.display_name'),
|
||||||
'url' => config('url.longurl'),
|
'url' => config('app.url'),
|
||||||
],
|
],
|
||||||
'children' => $items,
|
'children' => $items,
|
||||||
], 200, [
|
], 200, [
|
||||||
|
@ -183,8 +180,8 @@ class FeedsController extends Controller
|
||||||
$items[] = [
|
$items[] = [
|
||||||
'type' => 'entry',
|
'type' => 'entry',
|
||||||
'published' => $note->created_at,
|
'published' => $note->created_at,
|
||||||
'uid' => $note->longurl,
|
'uid' => $note->uri,
|
||||||
'url' => $note->longurl,
|
'url' => $note->uri,
|
||||||
'content' => [
|
'content' => [
|
||||||
'text' => $note->getRawOriginal('note'),
|
'text' => $note->getRawOriginal('note'),
|
||||||
'html' => $note->note,
|
'html' => $note->note,
|
||||||
|
@ -200,7 +197,7 @@ class FeedsController extends Controller
|
||||||
'author' => [
|
'author' => [
|
||||||
'type' => 'card',
|
'type' => 'card',
|
||||||
'name' => config('user.display_name'),
|
'name' => config('user.display_name'),
|
||||||
'url' => config('url.longurl'),
|
'url' => config('app.url'),
|
||||||
],
|
],
|
||||||
'children' => $items,
|
'children' => $items,
|
||||||
], 200, [
|
], 200, [
|
||||||
|
|
|
@ -10,9 +10,6 @@ use App\Models\Note;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class FrontPageController extends Controller
|
class FrontPageController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,9 +7,6 @@ namespace App\Http\Controllers;
|
||||||
use App\Models\Like;
|
use App\Models\Like;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class LikesController extends Controller
|
class LikesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -19,9 +19,6 @@ use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
|
||||||
use Monolog\Handler\StreamHandler;
|
use Monolog\Handler\StreamHandler;
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class MicropubController extends Controller
|
class MicropubController extends Controller
|
||||||
{
|
{
|
||||||
protected TokenService $tokenService;
|
protected TokenService $tokenService;
|
||||||
|
|
|
@ -22,9 +22,6 @@ use Lcobucci\JWT\Token\InvalidTokenStructure;
|
||||||
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
|
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
|
||||||
use Ramsey\Uuid\Uuid;
|
use Ramsey\Uuid\Uuid;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class MicropubMediaController extends Controller
|
class MicropubMediaController extends Controller
|
||||||
{
|
{
|
||||||
protected TokenService $tokenService;
|
protected TokenService $tokenService;
|
||||||
|
|
|
@ -14,8 +14,6 @@ use Jonnybarnes\IndieWeb\Numbers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo Need to sort out Twitter and webmentions!
|
* @todo Need to sort out Twitter and webmentions!
|
||||||
*
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
*/
|
||||||
class NotesController extends Controller
|
class NotesController extends Controller
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,9 +7,6 @@ namespace App\Http\Controllers;
|
||||||
use App\Models\Place;
|
use App\Models\Place;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class PlacesController extends Controller
|
class PlacesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,9 +6,6 @@ use App\Models\Note;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class SearchController extends Controller
|
class SearchController extends Controller
|
||||||
{
|
{
|
||||||
public function search(Request $request): View
|
public function search(Request $request): View
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use Illuminate\Http\RedirectResponse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class ShortURLsController extends Controller
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Short URL Controller
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This redirects the short urls to long ones
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redirect from '/' to the long url.
|
|
||||||
*/
|
|
||||||
public function baseURL(): RedirectResponse
|
|
||||||
{
|
|
||||||
return redirect(config('app.url'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redirect from '/@' to a twitter profile.
|
|
||||||
*/
|
|
||||||
public function twitter(): RedirectResponse
|
|
||||||
{
|
|
||||||
return redirect('https://twitter.com/jonnybarnes');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redirect a short url of this site out to a long one based on post type.
|
|
||||||
*
|
|
||||||
* Further redirects may happen.
|
|
||||||
*/
|
|
||||||
public function expandType(string $type, string $postId): RedirectResponse
|
|
||||||
{
|
|
||||||
if ($type === 't') {
|
|
||||||
$type = 'notes';
|
|
||||||
}
|
|
||||||
if ($type === 'b') {
|
|
||||||
$type = 'blog/s';
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect(config('app.url') . '/' . $type . '/' . $postId);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,9 +12,6 @@ use Illuminate\Http\Response;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
use Jonnybarnes\IndieWeb\Numbers;
|
use Jonnybarnes\IndieWeb\Numbers;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class WebMentionsController extends Controller
|
class WebMentionsController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,8 +10,6 @@ class CorsHeaders
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Handle an incoming request.
|
* Handle an incoming request.
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function handle(Request $request, Closure $next): Response
|
public function handle(Request $request, Closure $next): Response
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,8 +10,6 @@ class LinkHeadersMiddleware
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Handle an incoming request.
|
* Handle an incoming request.
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function handle(Request $request, Closure $next): Response
|
public function handle(Request $request, Closure $next): Response
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,8 +14,6 @@ class LocalhostSessionMiddleware
|
||||||
* Whilst we are developing locally, automatically log in as
|
* Whilst we are developing locally, automatically log in as
|
||||||
* `['me' => config('app.url')]` as I can’t manually log in as
|
* `['me' => config('app.url')]` as I can’t manually log in as
|
||||||
* a .localhost domain.
|
* a .localhost domain.
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function handle(Request $request, Closure $next): Response
|
public function handle(Request $request, Closure $next): Response
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,8 +13,6 @@ class MyAuthMiddleware
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Check the user is logged in.
|
* Check the user is logged in.
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function handle(Request $request, Closure $next): Response
|
public function handle(Request $request, Closure $next): Response
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,8 +10,6 @@ class ValidateSignature extends Middleware
|
||||||
* The names of the query string parameters that should be ignored.
|
* The names of the query string parameters that should be ignored.
|
||||||
*
|
*
|
||||||
* @var array<int, string>
|
* @var array<int, string>
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedProperty
|
|
||||||
*/
|
*/
|
||||||
protected $except = [
|
protected $except = [
|
||||||
// 'fbclid',
|
// 'fbclid',
|
||||||
|
|
|
@ -12,8 +12,6 @@ class VerifyMicropubToken
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Handle an incoming request.
|
* Handle an incoming request.
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function handle(Request $request, Closure $next): Response
|
public function handle(Request $request, Closure $next): Response
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,7 +53,7 @@ class ProcessWebMention implements ShouldQueue
|
||||||
// check webmention still references target
|
// check webmention still references target
|
||||||
// we try each type of mention (reply/like/repost)
|
// we try each type of mention (reply/like/repost)
|
||||||
if ($webmention->type === 'in-reply-to') {
|
if ($webmention->type === 'in-reply-to') {
|
||||||
if ($parser->checkInReplyTo($microformats, $this->note->longurl) === false) {
|
if ($parser->checkInReplyTo($microformats, $this->note->uri) === false) {
|
||||||
// it doesn’t so delete
|
// it doesn’t so delete
|
||||||
$webmention->delete();
|
$webmention->delete();
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ class ProcessWebMention implements ShouldQueue
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($webmention->type === 'like-of') {
|
if ($webmention->type === 'like-of') {
|
||||||
if ($parser->checkLikeOf($microformats, $this->note->longurl) === false) {
|
if ($parser->checkLikeOf($microformats, $this->note->uri) === false) {
|
||||||
// it doesn’t so delete
|
// it doesn’t so delete
|
||||||
$webmention->delete();
|
$webmention->delete();
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ class ProcessWebMention implements ShouldQueue
|
||||||
} // note we don’t need to do anything if it still is a like
|
} // note we don’t need to do anything if it still is a like
|
||||||
}
|
}
|
||||||
if ($webmention->type === 'repost-of') {
|
if ($webmention->type === 'repost-of') {
|
||||||
if ($parser->checkRepostOf($microformats, $this->note->longurl) === false) {
|
if ($parser->checkRepostOf($microformats, $this->note->uri) === false) {
|
||||||
// it doesn’t so delete
|
// it doesn’t so delete
|
||||||
$webmention->delete();
|
$webmention->delete();
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ class ProcessWebMention implements ShouldQueue
|
||||||
$type = $parser->getMentionType($microformats); // throw error here?
|
$type = $parser->getMentionType($microformats); // throw error here?
|
||||||
dispatch(new SaveProfileImage($microformats));
|
dispatch(new SaveProfileImage($microformats));
|
||||||
$webmention->source = $this->source;
|
$webmention->source = $this->source;
|
||||||
$webmention->target = $this->note->longurl;
|
$webmention->target = $this->note->uri;
|
||||||
$webmention->commentable_id = $this->note->id;
|
$webmention->commentable_id = $this->note->id;
|
||||||
$webmention->commentable_type = Note::class;
|
$webmention->commentable_type = Note::class;
|
||||||
$webmention->type = $type;
|
$webmention->type = $type;
|
||||||
|
|
|
@ -45,7 +45,7 @@ class SendWebMentions implements ShouldQueue
|
||||||
$guzzle = resolve(Client::class);
|
$guzzle = resolve(Client::class);
|
||||||
$guzzle->post($endpoint, [
|
$guzzle->post($endpoint, [
|
||||||
'form_params' => [
|
'form_params' => [
|
||||||
'source' => $this->note->longurl,
|
'source' => $this->note->uri,
|
||||||
'target' => $url,
|
'target' => $url,
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
@ -61,7 +61,7 @@ class SendWebMentions implements ShouldQueue
|
||||||
public function discoverWebmentionEndpoint(string $url): ?string
|
public function discoverWebmentionEndpoint(string $url): ?string
|
||||||
{
|
{
|
||||||
// let’s not send webmentions to myself
|
// let’s not send webmentions to myself
|
||||||
if (parse_url($url, PHP_URL_HOST) === config('url.longurl')) {
|
if (parse_url($url, PHP_URL_HOST) === parse_url(config('app.url'), PHP_URL_HOST)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (Str::startsWith($url, '/notes/tagged/')) {
|
if (Str::startsWith($url, '/notes/tagged/')) {
|
||||||
|
|
|
@ -26,7 +26,7 @@ class Bookmark extends Model
|
||||||
return $this->belongsToMany('App\Models\Tag');
|
return $this->belongsToMany('App\Models\Tag');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function longurl(): Attribute
|
protected function local_uri(): Attribute
|
||||||
{
|
{
|
||||||
return Attribute::get(
|
return Attribute::get(
|
||||||
get: fn () => config('app.url') . '/bookmarks/' . $this->id,
|
get: fn () => config('app.url') . '/bookmarks/' . $this->id,
|
||||||
|
|
|
@ -124,7 +124,7 @@ class Note extends Model
|
||||||
public function getNoteAttribute(?string $value): ?string
|
public function getNoteAttribute(?string $value): ?string
|
||||||
{
|
{
|
||||||
if ($value === null && $this->place !== null) {
|
if ($value === null && $this->place !== null) {
|
||||||
$value = '📍: <a href="' . $this->place->longurl . '">' . $this->place->name . '</a>';
|
$value = '📍: <a href="' . $this->place->uri . '">' . $this->place->name . '</a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// if $value is still null, just return null
|
// if $value is still null, just return null
|
||||||
|
@ -172,16 +172,11 @@ class Note extends Model
|
||||||
return (string) resolve(Numbers::class)->numto60($this->id);
|
return (string) resolve(Numbers::class)->numto60($this->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLongurlAttribute(): string
|
public function getUriAttribute(): string
|
||||||
{
|
{
|
||||||
return config('app.url') . '/notes/' . $this->nb60id;
|
return config('app.url') . '/notes/' . $this->nb60id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShorturlAttribute(): string
|
|
||||||
{
|
|
||||||
return config('url.shorturl') . '/notes/' . $this->nb60id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getIso8601Attribute(): string
|
public function getIso8601Attribute(): string
|
||||||
{
|
{
|
||||||
return $this->updated_at->toISO8601String();
|
return $this->updated_at->toISO8601String();
|
||||||
|
|
|
@ -74,24 +74,10 @@ class Place extends Model
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function longurl(): Attribute
|
|
||||||
{
|
|
||||||
return Attribute::get(
|
|
||||||
get: fn ($value, $attributes) => config('app.url') . '/places/' . $attributes['slug'],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function shorturl(): Attribute
|
|
||||||
{
|
|
||||||
return Attribute::get(
|
|
||||||
get: fn ($value, $attributes) => config('url.shorturl') . '/places/' . $attributes['slug'],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function uri(): Attribute
|
protected function uri(): Attribute
|
||||||
{
|
{
|
||||||
return Attribute::get(
|
return Attribute::get(
|
||||||
get: fn () => $this->longurl,
|
get: static fn ($value, $attributes) => config('app.url') . '/places/' . $attributes['slug'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,15 +9,10 @@ use App\Models\Tag;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo Do we need psalm-suppress for these observer methods?
|
|
||||||
*/
|
|
||||||
class NoteObserver
|
class NoteObserver
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Listen to the Note created event.
|
* Listen to the Note created event.=
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function created(Note $note): void
|
public function created(Note $note): void
|
||||||
{
|
{
|
||||||
|
@ -39,9 +34,7 @@ class NoteObserver
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen to the Note updated event.
|
* Listen to the Note updated event.=
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function updated(Note $note): void
|
public function updated(Note $note): void
|
||||||
{
|
{
|
||||||
|
@ -65,9 +58,7 @@ class NoteObserver
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen to the Note deleting event.
|
* Listen to the Note deleting event.=
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function deleting(Note $note): void
|
public function deleting(Note $note): void
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,9 +5,6 @@ namespace App\Providers;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
use Laravel\Horizon\HorizonApplicationServiceProvider;
|
use Laravel\Horizon\HorizonApplicationServiceProvider;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class HorizonServiceProvider extends HorizonApplicationServiceProvider
|
class HorizonServiceProvider extends HorizonApplicationServiceProvider
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,6 +27,6 @@ class HCardService
|
||||||
$data['longitude'] = Arr::get($request, 'longitude');
|
$data['longitude'] = Arr::get($request, 'longitude');
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolve(PlaceService::class)->createPlace($data)->longurl;
|
return resolve(PlaceService::class)->createPlace($data)->uri;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,17 +18,17 @@ class HEntryService
|
||||||
public function process(array $request, ?string $client = null): ?string
|
public function process(array $request, ?string $client = null): ?string
|
||||||
{
|
{
|
||||||
if (Arr::get($request, 'properties.like-of') || Arr::get($request, 'like-of')) {
|
if (Arr::get($request, 'properties.like-of') || Arr::get($request, 'like-of')) {
|
||||||
return resolve(LikeService::class)->create($request)->longurl;
|
return resolve(LikeService::class)->create($request)->url;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Arr::get($request, 'properties.bookmark-of') || Arr::get($request, 'bookmark-of')) {
|
if (Arr::get($request, 'properties.bookmark-of') || Arr::get($request, 'bookmark-of')) {
|
||||||
return resolve(BookmarkService::class)->create($request)->longurl;
|
return resolve(BookmarkService::class)->create($request)->uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Arr::get($request, 'properties.name') || Arr::get($request, 'name')) {
|
if (Arr::get($request, 'properties.name') || Arr::get($request, 'name')) {
|
||||||
return resolve(ArticleService::class)->create($request)->longurl;
|
return resolve(ArticleService::class)->create($request)->link;
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolve(NoteService::class)->create($request, $client)->longurl;
|
return resolve(NoteService::class)->create($request, $client)->uri;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Here we set the long and short URLs our app shall use
|
|
||||||
* You can override these settings in the .env file
|
|
||||||
*/
|
|
||||||
|
|
||||||
return [
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Application Long URL
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The long URL for the application
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'longurl' => env('APP_LONGURL', 'longurl.local'),
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Application Short URL
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The short URL for the application
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'shorturl' => env('APP_SHORTURL', 'shorturl.local'),
|
|
||||||
|
|
||||||
];
|
|
|
@ -7,8 +7,6 @@ use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*
|
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Article>
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Article>
|
||||||
*/
|
*/
|
||||||
class ArticleFactory extends Factory
|
class ArticleFactory extends Factory
|
||||||
|
|
|
@ -5,8 +5,6 @@ namespace Database\Factories;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*
|
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Bio>
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Bio>
|
||||||
*/
|
*/
|
||||||
class BioFactory extends Factory
|
class BioFactory extends Factory
|
||||||
|
|
|
@ -7,8 +7,6 @@ use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*
|
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Bookmark>
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Bookmark>
|
||||||
*/
|
*/
|
||||||
class BookmarkFactory extends Factory
|
class BookmarkFactory extends Factory
|
||||||
|
|
|
@ -7,8 +7,6 @@ use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*
|
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Contact>
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Contact>
|
||||||
*/
|
*/
|
||||||
class ContactFactory extends Factory
|
class ContactFactory extends Factory
|
||||||
|
|
|
@ -7,8 +7,6 @@ use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*
|
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Like>
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Like>
|
||||||
*/
|
*/
|
||||||
class LikeFactory extends Factory
|
class LikeFactory extends Factory
|
||||||
|
|
|
@ -7,8 +7,6 @@ use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*
|
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Media>
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Media>
|
||||||
*/
|
*/
|
||||||
class MediaFactory extends Factory
|
class MediaFactory extends Factory
|
||||||
|
|
|
@ -6,8 +6,6 @@ use App\Models\MicropubClient;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*
|
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\MicropubClient>
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\MicropubClient>
|
||||||
*/
|
*/
|
||||||
class MicropubClientFactory extends Factory
|
class MicropubClientFactory extends Factory
|
||||||
|
|
|
@ -8,8 +8,6 @@ use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*
|
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Note>
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Note>
|
||||||
*/
|
*/
|
||||||
class NoteFactory extends Factory
|
class NoteFactory extends Factory
|
||||||
|
|
|
@ -6,8 +6,6 @@ use App\Models\Place;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*
|
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Place>
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Place>
|
||||||
*/
|
*/
|
||||||
class PlaceFactory extends Factory
|
class PlaceFactory extends Factory
|
||||||
|
|
|
@ -5,8 +5,6 @@ namespace Database\Factories;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*
|
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\SyndicationTarget>
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\SyndicationTarget>
|
||||||
*/
|
*/
|
||||||
class SyndicationTargetFactory extends Factory
|
class SyndicationTargetFactory extends Factory
|
||||||
|
|
|
@ -6,8 +6,6 @@ use App\Models\Tag;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*
|
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Tag>
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Tag>
|
||||||
*/
|
*/
|
||||||
class TagFactory extends Factory
|
class TagFactory extends Factory
|
||||||
|
|
|
@ -7,8 +7,6 @@ use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*
|
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
||||||
*/
|
*/
|
||||||
class UserFactory extends Factory
|
class UserFactory extends Factory
|
||||||
|
|
|
@ -6,8 +6,6 @@ use App\Models\WebMention;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*
|
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\WebMention>
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\WebMention>
|
||||||
*/
|
*/
|
||||||
class WebMentionFactory extends Factory
|
class WebMentionFactory extends Factory
|
||||||
|
|
|
@ -11,8 +11,6 @@ class ArticlesTableSeeder extends Seeder
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Seed the articles table.
|
* Seed the articles table.
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,9 +5,6 @@ namespace Database\Seeders;
|
||||||
use App\Models\Bio;
|
use App\Models\Bio;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class BioSeeder extends Seeder
|
class BioSeeder extends Seeder
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,8 +10,6 @@ class BookmarksTableSeeder extends Seeder
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Seed the bookmarks table.
|
* Seed the bookmarks table.
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,8 +11,6 @@ class ClientsTableSeeder extends Seeder
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Seed the clients table.
|
* Seed the clients table.
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,8 +10,6 @@ class ContactsTableSeeder extends Seeder
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Seed the contacts table.
|
* Seed the contacts table.
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,9 +4,6 @@ namespace Database\Seeders;
|
||||||
|
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-suppress UnusedClass
|
|
||||||
*/
|
|
||||||
class DatabaseSeeder extends Seeder
|
class DatabaseSeeder extends Seeder
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -12,8 +12,6 @@ class LikesTableSeeder extends Seeder
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Seed the likes table.
|
* Seed the likes table.
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,8 +14,6 @@ class NotesTableSeeder extends Seeder
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Seed the notes table.
|
* Seed the notes table.
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,8 +9,6 @@ class PlacesTableSeeder extends Seeder
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Seed the places table.
|
* Seed the places table.
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,8 +9,6 @@ class UsersTableSeeder extends Seeder
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Seed the users table.
|
* Seed the users table.
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,8 +9,6 @@ class WebMentionsTableSeeder extends Seeder
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Seed the webmentions table.
|
* Seed the webmentions table.
|
||||||
*
|
|
||||||
* @psalm-suppress PossiblyUnusedMethod
|
|
||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
|
|
1379
package-lock.json
generated
1379
package-lock.json
generated
File diff suppressed because it is too large
Load diff
18
package.json
18
package.json
|
@ -7,21 +7,23 @@
|
||||||
"license": "CC0-1.0",
|
"license": "CC0-1.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.6.0",
|
"@eslint/js": "^9.6.0",
|
||||||
"@stylistic/eslint-plugin": "^3.0.0",
|
"@stylistic/eslint-plugin": "^4.2.0",
|
||||||
|
"esbuild": "^0.25.2",
|
||||||
"eslint": "^9.7.0",
|
"eslint": "^9.7.0",
|
||||||
"globals": "^15.8.0",
|
"globals": "^16.0.0",
|
||||||
|
"lightningcss": "^1.29.3",
|
||||||
|
"lightningcss-cli": "^1.29.3",
|
||||||
"stylelint": "^16.7.0",
|
"stylelint": "^16.7.0",
|
||||||
"stylelint-config-standard": "^37.0.0"
|
"stylelint-config-standard": "^38.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"eslint": "eslint public/assets/js/*.js",
|
"eslint": "eslint public/assets/js/*.js",
|
||||||
"stylelint": "stylelint public/assets/css/*.css",
|
"stylelint": "stylelint resources/css/*.css",
|
||||||
"lint": "npm run eslint && npm run stylelint",
|
"lint": "npm run eslint && npm run stylelint",
|
||||||
|
"lightningcss": "lightningcss --output-dir public/assets/css --sourcemap --bundle --minify resources/css/app.css",
|
||||||
|
"fix-sourcemap": "./scripts/fix-sourcemap.sh",
|
||||||
|
"build-css": "npm run lightningcss && npm run fix-sourcemap",
|
||||||
"compress": "./scripts/compress.sh",
|
"compress": "./scripts/compress.sh",
|
||||||
"build": "npm run lint && npm run compress"
|
"build": "npm run lint && npm run compress"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@11ty/is-land": "^4.0.0",
|
|
||||||
"@zachleat/snow-fall": "^1.0.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
plugins: {
|
|
||||||
'postcss-import': {},
|
|
||||||
'autoprefixer': {},
|
|
||||||
'@csstools/postcss-oklab-function': {
|
|
||||||
preserve: true
|
|
||||||
},
|
|
||||||
'postcss-nesting': {},
|
|
||||||
'postcss-combine-media-query': {},
|
|
||||||
'postcss-combine-duplicated-selectors': {
|
|
||||||
removeDuplicatedProperties: true,
|
|
||||||
removeDuplicatedValues: true
|
|
||||||
},
|
|
||||||
'cssnano': { preset: 'default' },
|
|
||||||
}
|
|
||||||
};
|
|
18
psalm.xml
18
psalm.xml
|
@ -1,18 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<psalm
|
|
||||||
errorLevel="7"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="https://getpsalm.org/schema/config"
|
|
||||||
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
|
|
||||||
findUnusedBaselineEntry="true"
|
|
||||||
findUnusedCode="true"
|
|
||||||
>
|
|
||||||
<projectFiles>
|
|
||||||
<directory name="app"/>
|
|
||||||
<directory name="database/factories"/>
|
|
||||||
<directory name="database/seeders"/>
|
|
||||||
<ignoreFiles>
|
|
||||||
<directory name="vendor"/>
|
|
||||||
</ignoreFiles>
|
|
||||||
</projectFiles>
|
|
||||||
<plugins><pluginClass class="Psalm\LaravelPlugin\Plugin"/></plugins></psalm>
|
|
|
@ -1,8 +1,2 @@
|
||||||
@import url('variables.css');
|
:root{--font-family-headings:"Rockwell","Rockwell Nova","Roboto Slab","DejaVu Serif","Sitka Small",serif;--font-family-body:"Charter","Bitstream Charter","Sitka Text","Cambria",serif;--font-family-monospace:ui-monospace,"Cascadia Code","Source Code Pro","Menlo","Consolas","DejaVu Sans Mono",monospace;--font-size-sm:.75rem;--font-size-base:1rem;--font-size-md:1.25rem;--font-size-lg:1.5rem;--font-size-xl:1.75rem;--font-size-xxl:2rem;--font-size-xxxl:2.25rem;--color-primary:oklch(36.8% .1 125.505);--color-secondary:oklch(96.3% .1 125.505);--color-link:oklch(48.09% .146 241.41);--color-link-visited:oklch(70.44% .21 304.41);--color-primary-shadow:oklch(19.56% .054 125.505/.4);--rss-color-link:oklch(67.59% .189 42.04);--color-danger:oklch(64.41% .281 23.29);--color-danger-shadow:oklch(64.41% .281 23.29/.1)}body{font-family:var(--font-family-body);font-size:var(--font-size-md)}code{font-family:var(--font-family-monospace)}h1,h2,h3,h4,h5,h6{font-family:var(--font-family-headings)}.grid{grid-template-rows:min-content 1fr min-content;grid-template-columns:5vw 1fr 5vw;row-gap:1rem;display:grid}#site-header{grid-area:1/2/2/3;& .rss-icon{& svg{width:auto;height:1rem}}}main{grid-area:2/2/3/3}.h-feed{flex-direction:column;gap:2rem;display:flex}.h-entry{& p:first-of-type,& h1:first-of-type{margin-block-start:0}}.pagination{margin-block-start:1rem}footer{grid-area:3/2/4/3;& .iwc-logo{max-width:85vw}& .footer-actions{flex-direction:row;gap:1rem;display:flex}}body{background-color:var(--color-secondary);color:var(--color-primary)}a{color:var(--color-link);&:visited{color:var(--color-link-visited)}&.auth:visited{color:var(--color-link)}}#site-header{& a:visited{color:var(--color-link)}& .rss-icon{& svg{color:var(--rss-color-link)}}}.hljs{border-radius:.5rem}.h-card{& .hovercard{z-index:100;box-shadow:0 .5rem .5rem .5rem var(--color-primary-shadow);background-color:var(--color-secondary);opacity:0;border-radius:1rem;flex-direction:column;gap:.5rem;width:fit-content;padding:1rem;transition:opacity .5s ease-in-out;display:none;position:absolute;& .u-photo{max-width:6rem}& .social-icon{width:1rem;height:1rem}}&:hover{& .hovercard{opacity:1;display:flex}}}.h-entry{border-inline-start:1px solid var(--color-primary);padding-inline-start:.5rem;& .reply-to{font-style:italic}& .post-info{& a{text-decoration:none}}& .note-metadata{flex-direction:row;gap:1rem;display:flex;& .replies,& .likes,& .reposts{flex-direction:row;align-items:center;gap:.5rem;display:inline-flex}& .syndication-links{flex-flow:wrap;& a{text-decoration:none;& svg{width:1rem;height:1rem}}}}}.feather{stroke:currentColor;stroke-width:2px;stroke-linecap:round;stroke-linejoin:round;fill:none;width:24px;height:24px}.sr-only{clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}main{&>.u-comment{border-inline-start:1px solid var(--color-primary);margin-block-start:2rem;margin-inline-start:2rem;padding-inline-start:.5rem;& .mini-h-card{flex-direction:row;align-items:baseline;display:inline-flex;& .u-photo{border-radius:50%;width:2rem;height:2rem;margin-block-end:.5rem}}}& .notes-subtitle{font-size:1.2rem;font-weight:600}& .webmentions-author-list{flex-flow:wrap;gap:1rem;display:flex;& img{border-radius:50%;width:4rem;height:4rem}}}.indieauth{& .error{color:var(--color-danger);background-color:var(--color-danger-shadow);border:1px solid var(--color-danger);border-radius:.5rem;width:fit-content;margin-block-end:1rem;padding-block:.5rem;padding-inline:1rem;display:flex}}
|
||||||
@import url('fonts.css');
|
/*# sourceMappingURL=/assets/css/app.css.map */
|
||||||
@import url('layout.css');
|
|
||||||
@import url('colours.css');
|
|
||||||
@import url('code.css');
|
|
||||||
@import url('content.css');
|
|
||||||
@import url('notes.css');
|
|
||||||
@import url('indieauth.css');
|
|
||||||
|
|
Binary file not shown.
1
public/assets/css/app.css.map
Normal file
1
public/assets/css/app.css.map
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue