Compare commits

..

74 commits

Author SHA1 Message Date
07db68882b Merge pull request 'MTM Laravel v12' (#31) from develop into main
Some checks failed
Deploy / Deploy (release) Has been cancelled
Reviewed-on: #31
2025-04-04 18:10:46 +02:00
13786584a2 Merge pull request 'MTM WebMention username fix & snow fall' (#21) from develop into main
Some checks failed
Deploy / Deploy (release) Has been cancelled
Reviewed-on: #21
2024-11-30 17:01:53 +01:00
6d867fcc71 Merge pull request 'MTM Host images locally' (#12) from develop into main
Some checks failed
Deploy / Deploy (release) Has been cancelled
Reviewed-on: #12
2024-10-26 15:02:56 +02:00
7dd85a3988 Merge pull request 'MTM Improve customisability' (#8) from develop into main
Some checks failed
Deploy / Deploy (release) Has been cancelled
Reviewed-on: #8
2024-08-29 19:25:33 +02:00
863db8e491 Merge pull request 'MTM Fix how scopes are stored in the IndieAuth flow' (#4) from develop into main
Some checks failed
Deploy / Deploy (release) Has been cancelled
Reviewed-on: #4
2024-08-03 14:28:48 +02:00
b7d7db60e7
Merge pull request #1474 from jonnybarnes/develop
MTM Fix scope checks
2024-07-13 15:20:46 +01:00
0336744322
Merge pull request #1454 from jonnybarnes/develop
MTM Fix issuing of tokens
2024-06-30 11:20:41 +01:00
7b13f91cc4
Merge pull request #1445 from jonnybarnes/develop
MTM Parse scope value from authorization URL correctly
2024-06-22 21:01:34 +01:00
f689128afc
Merge pull request #1442 from jonnybarnes/develop
MTM Save full url during login
2024-06-22 20:33:36 +01:00
2e624d9565
Merge pull request #1439 from jonnybarnes/develop
Improve IndieAuth links in the html head
2024-06-22 18:46:16 +01:00
d60117cd1d
Merge pull request #1436 from jonnybarnes/develop
New IndieAuth endpoint
2024-06-22 18:29:29 +01:00
fabe9d662b
Merge pull request #1371 from jonnybarnes/develop
MTM Bluesky Syndication
2024-03-23 21:33:39 +00:00
507bac08f2
Merge pull request #1363 from jonnybarnes/develop
MTM Remove CSP header
2024-03-23 15:13:55 +00:00
c0802f8792
Merge pull request #1361 from jonnybarnes/develop
MTM Fix some endpoints
2024-03-23 14:29:33 +00:00
c907bcde0c
Merge pull request #1357 from jonnybarnes/develop
MTM Update CSP
2024-03-22 19:17:22 +00:00
784f4cb44a
Merge pull request #1354 from jonnybarnes/develop
MTM Fix showing webmentions
2024-03-22 19:00:39 +00:00
528e981d7c
Merge pull request #1352 from jonnybarnes/develop
MTM Add Flare config back
2024-03-22 18:33:45 +00:00
5f8d6ca882
Merge pull request #1348 from jonnybarnes/develop
MTM Fix WebMentions
2024-03-22 17:53:24 +00:00
d56306e57b
Merge pull request #1346 from jonnybarnes/develop
MTM Laravel 11
2024-03-22 15:31:33 +00:00
43c654d9e7
Merge pull request #1316 from jonnybarnes/develop
MTM Fix error in SendWebMention job
2024-03-02 10:21:49 +00:00
a7c8e58abd
Merge pull request #1303 from jonnybarnes/develop
MTM Fix fonts
2024-02-23 16:50:55 +00:00
b40f10cada
Merge pull request #1300 from jonnybarnes/develop
MTM Switch fonts
2024-02-23 16:41:54 +00:00
deba175f8f
Merge pull request #1288 from jonnybarnes/develop
MTM: Remove snow effect
2024-02-17 18:28:13 +00:00
c0c8e5262b
Merge pull request #1206 from jonnybarnes/develop
MTM Simplify build steps
2023-12-22 08:03:01 +00:00
469d11ca7a
Merge pull request #1191 from jonnybarnes/develop
MTM Hopefully fix snow
2023-12-17 15:01:17 +00:00
6ff247d58b
Merge pull request #1188 from jonnybarnes/develop
MTM Add snow
2023-12-17 14:45:57 +00:00
d5bac002c4
Merge pull request #1155 from jonnybarnes/develop
MTM Show Webmentions
2023-12-02 14:53:51 +00:00
481d9e22bb
Merge pull request #1123 from jonnybarnes/develop
MTM Updated CSS and Deploy script
2023-11-11 19:25:04 +00:00
335acb130e
Merge pull request #1103 from jonnybarnes/develop
MTM Passkey Support
2023-10-27 20:17:14 +00:00
f375e4217f
Merge pull request #922 from jonnybarnes/develop
MTM Fix error in SaveProfileImage
2023-06-17 20:01:52 +01:00
3dfe99aac7
Merge pull request #919 from jonnybarnes/develop
MTM Fix routing for Article links
2023-06-16 13:18:28 +01:00
577d821709
Merge pull request #909 from jonnybarnes/develop
MTM Fix use of config variables
2023-06-11 17:01:56 +01:00
66f4f856a6
Merge pull request #906 from jonnybarnes/develop
MTM Stop note IDs being too large
2023-06-11 15:22:55 +01:00
73bc0b5338
Merge pull request #901 from jonnybarnes/develop
MTM Add Flare support
2023-06-09 14:15:30 +01:00
2f40e83568
Merge pull request #874 from jonnybarnes/develop
MTM Use separate CSS file in production
2023-05-29 13:04:38 +01:00
b2ef970810
Merge pull request #865 from jonnybarnes/develop
MTM Fix CSP for webpack added style rules
2023-05-27 19:40:02 +01:00
2b2826212f
Merge pull request #863 from jonnybarnes/develop
MTM Fix compiled assets for prod
2023-05-27 18:08:09 +01:00
94bb8c204b
Merge pull request #860 from jonnybarnes/develop
MTM Fix schema update
2023-05-27 16:58:22 +01:00
87d49bddde
Merge pull request #857 from jonnybarnes/develop
MTM: Some small tweaks and dependency updates
2023-05-27 15:41:41 +01:00
9383ed8d0b
Merge pull request #817 from jonnybarnes/develop
MTM Remove Mapbox links
2023-05-04 18:49:21 +01:00
2962675f9d
Merge pull request #770 from jonnybarnes/develop
MTM Re-add search functionality
2023-04-12 10:19:14 +01:00
8532ee36d3
Merge pull request #766 from jonnybarnes/develop
MTM Switch bio to be stored in the database
2023-04-11 17:50:34 +01:00
22447b6027
Merge pull request #758 from jonnybarnes/develop
MTM 2023 Redesign v1
2023-04-08 17:07:18 +01:00
fcf0b4a778
Merge pull request #670 from jonnybarnes/develop
MTM: Laravel 10
2023-02-18 10:03:06 +00:00
cc782bc39a
Merge pull request #641 from jonnybarnes/develop
MTM: Add PHP 8.2 Support
2023-02-04 12:45:44 +00:00
054bba1da9
Merge pull request #639 from jonnybarnes/develop
MTM: Recent work
2023-02-04 12:22:23 +00:00
22e3eaab23
Merge pull request #559 from jonnybarnes/develop
MTM Update Failed Jobs table
2022-11-21 19:15:09 +00:00
e0efd19ef9
Merge pull request #553 from jonnybarnes/develop
MTM More Media Endpoint Improvements
2022-11-20 17:30:25 +00:00
0cd6f81a09
Merge pull request #551 from jonnybarnes/develop
MTM Improve Media Endpoint
2022-11-18 17:32:39 +00:00
30c9b2e248
Merge pull request #535 from jonnybarnes/develop
MTM Handle finding webmention targets better
2022-11-09 20:10:55 +00:00
52ac67ba7a
Merge pull request #525 from jonnybarnes/develop
MTM Post Markdown content to Mastodon
2022-11-06 10:32:03 +00:00
272a5ea2fd
Merge pull request #522 from jonnybarnes/develop
MTM Mastodon syndication
2022-11-04 17:22:22 +00:00
0bea4a1e95
Merge pull request #499 from jonnybarnes/develop
MTM Simplify migrations
2022-10-24 21:18:58 +01:00
8ec738a765
Merge pull request #497 from jonnybarnes/develop
MTM Fix error saving syndication data
2022-10-24 17:45:22 +01:00
2f548725db
Merge pull request #494 from jonnybarnes/develop
MTM Store synidaction targets in the database
2022-10-24 14:28:06 +01:00
f6546e2335
Merge pull request #477 from jonnybarnes/develop
MTM Update Twitter syndication logo
2022-10-16 18:16:38 +01:00
d52b8a3e83
Merge pull request #473 from jonnybarnes/develop
MTM Fix IndieAuth sign in
2022-10-15 16:24:35 +01:00
46133be181
Merge pull request #445 from jonnybarnes/develop
MTM Reworked indieauth checking in token endpoint
2022-09-24 19:23:18 +01:00
0faf896e8f
Merge pull request #443 from jonnybarnes/develop
MTM Fix IndieAuth sign in
2022-09-24 18:42:27 +01:00
374e231a6b
Merge pull request #420 from jonnybarnes/develop
MTM Use env for cookie prefix
2022-09-10 13:50:49 +01:00
729c52df2f
Merge pull request #418 from jonnybarnes/develop
MTM JWT and Cookie fixes
2022-09-10 13:31:24 +01:00
ac19c02e76
Merge pull request #380 from jonnybarnes/develop
MTM More link fixes
2022-08-21 09:00:38 +01:00
0289f9f0b0
Merge pull request #378 from jonnybarnes/develop
MTM Fixing links
2022-08-20 15:31:34 +01:00
14a10472a6
Merge pull request #365 from jonnybarnes/develop
MTM Add tagged bookmarks page
2022-08-14 18:03:30 +01:00
b74bdd01ef
Merge pull request #362 from jonnybarnes/develop
MTM: Fix some links
2022-08-13 20:30:08 +01:00
9c059f822f
Merge pull request #293 from jonnybarnes/develop
MTM Mentions Improvements
2022-07-09 12:03:07 +01:00
75e369992d
Merge pull request #268 from jonnybarnes/develop
MTM Deploy tags
2022-06-04 17:24:37 +01:00
a18f7b2d03
Merge pull request #265 from jonnybarnes/develop
MTM Dependency updates and HTML Sanitizer
2022-06-04 11:16:23 +01:00
7d1738964a
Merge pull request #261 from jonnybarnes/develop
MTM: Laravel 9
2022-05-15 17:20:12 +01:00
77004ec7d4
Merge pull request #246 from jonnybarnes/develop
MTM: Syndication links style fix
2022-01-08 21:25:14 +00:00
3f891b580c
Merge pull request #244 from jonnybarnes/develop
MTM: Various dependency updates and new deployment code
2022-01-08 19:58:35 +00:00
38f3244e31
Merge pull request #220 from jonnybarnes/develop
MTM: PHP8 support, and PostCSS Webpack work
2020-12-31 14:55:46 +00:00
650d54292e
Merge pull request #215 from jonnybarnes/develop
MTM: Get main branch up to date
2020-11-08 11:14:29 +00:00
c40548be73
Merge pull request #114 from jonnybarnes/develop
MTM: recent work on Horizon
2019-03-23 16:10:06 +00:00
188 changed files with 2114 additions and 1782 deletions

14
.env.dusk.testing Normal file
View file

@ -0,0 +1,14 @@
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

View file

@ -4,6 +4,8 @@ APP_KEY=
APP_DEBUG=true
APP_TIMEZONE=UTC
APP_URL=https://example.com
APP_LONGURL=example.com
APP_SHORTURL=examp.le
APP_LOCALE=en
APP_FALLBACK_LOCALE=en

70
.env.github Normal file
View file

@ -0,0 +1,70 @@
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
View file

@ -5,3 +5,7 @@
*.html diff=html
*.md diff=markdown
*.php diff=php
/.github export-ignore
CHANGELOG.md export-ignore
.styleci.yml export-ignore

17
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,17 @@
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 Normal file
View file

@ -0,0 +1,144 @@
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 Normal file
View file

@ -0,0 +1,65 @@
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 Normal file
View file

@ -0,0 +1,38 @@
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
View file

@ -4,6 +4,7 @@
/public/coverage
/public/hot
/public/files
/public/fonts
/public/storage
/storage/*.key
/vendor

5
.phpactor.json Normal file
View file

@ -0,0 +1,5 @@
{
"$schema": "/Users/jonny/git/phpactor/phpactor.schema.json",
"language_server_phpstan.enabled": false,
"language_server_psalm.enabled": true
}

9
.styleci.yml Normal file
View file

@ -0,0 +1,9 @@
php:
preset: laravel
disabled:
- no_unused_imports
finder:
not-name:
- index.php
js: true
css: true

View file

@ -8,6 +8,8 @@ use Illuminate\Support\Facades\DB;
/**
* @codeCoverageIgnore
*
* @psalm-suppress UnusedClass
*/
class MigratePlaceDataFromPostgis extends Command
{

View file

@ -9,6 +9,9 @@ use Illuminate\Console\Command;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Illuminate\FileSystem\FileSystem;
/**
* @psalm-suppress UnusedClass
*/
class ParseCachedWebMentions extends Command
{
/**

View file

@ -8,6 +8,9 @@ use App\Jobs\DownloadWebMention;
use App\Models\WebMention;
use Illuminate\Console\Command;
/**
* @psalm-suppress UnusedClass
*/
class ReDownloadWebMentions extends Command
{
/**

View file

@ -9,6 +9,9 @@ use App\Models\Article;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class ArticlesController extends Controller
{
public function index(): View

View file

@ -10,6 +10,9 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class BioController extends Controller
{
public function show(): View

View file

@ -9,6 +9,9 @@ use App\Models\MicropubClient;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class ClientsController extends Controller
{
/**

View file

@ -12,6 +12,9 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Arr;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class ContactsController extends Controller
{
/**

View file

@ -7,6 +7,9 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class HomeController extends Controller
{
/**

View file

@ -10,6 +10,9 @@ use App\Models\Like;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class LikesController extends Controller
{
/**

View file

@ -11,6 +11,9 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class NotesController extends Controller
{
/**

View file

@ -18,7 +18,6 @@ use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;
use ParagonIE\ConstantTime\Base64UrlSafe;
use Random\RandomException;
use Throwable;
use Webauthn\AttestationStatement\AttestationStatementSupportManager;
use Webauthn\AttestationStatement\NoneAttestationStatementSupport;
@ -39,6 +38,9 @@ use Webauthn\PublicKeyCredentialRpEntity;
use Webauthn\PublicKeyCredentialSource;
use Webauthn\PublicKeyCredentialUserEntity;
/**
* @psalm-suppress UnusedClass
*/
class PasskeysController extends Controller
{
public function index(): View
@ -50,26 +52,22 @@ class PasskeysController extends Controller
return view('admin.passkeys.index', compact('passkeys'));
}
/**
* @throws RandomException
* @throws \JsonException
*/
public function getCreateOptions(Request $request): JsonResponse
public function getCreateOptions(): JsonResponse
{
/** @var User $user */
$user = auth()->user();
// RP Entity i.e. the application
$rpEntity = PublicKeyCredentialRpEntity::create(
name: config('app.name'),
id: config('app.url'),
config('app.name'),
config('url.longurl'),
);
// User Entity
$userEntity = PublicKeyCredentialUserEntity::create(
name: $user->name,
id: (string) $user->id,
displayName: $user->name,
$user->name,
(string) $user->id,
$user->name,
);
// Challenge
@ -87,38 +85,25 @@ class PasskeysController extends Controller
$authenticatorSelectionCriteria = AuthenticatorSelectionCriteria::create(
userVerification: AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_REQUIRED,
residentKey: AuthenticatorSelectionCriteria::RESIDENT_KEY_REQUIREMENT_REQUIRED,
requireResidentKey: true,
);
$publicKeyCredentialCreationOptions = PublicKeyCredentialCreationOptions::create(
rp: $rpEntity,
user: $userEntity,
challenge: $challenge,
pubKeyCredParams: $pubKeyCredParams,
$options = PublicKeyCredentialCreationOptions::create(
$rpEntity,
$userEntity,
$challenge,
$pubKeyCredParams,
authenticatorSelection: $authenticatorSelectionCriteria,
attestation: PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE
);
$attestationStatementSupportManager = new AttestationStatementSupportManager;
$attestationStatementSupportManager->add(new NoneAttestationStatementSupport);
$webauthnSerializerFactory = new WebauthnSerializerFactory(
attestationStatementSupportManager: $attestationStatementSupportManager
);
$webauthnSerializer = $webauthnSerializerFactory->create();
$publicKeyCredentialCreationOptions = $webauthnSerializer->serialize(
data: $publicKeyCredentialCreationOptions,
format: 'json'
);
$options = json_encode($options, JSON_THROW_ON_ERROR);
$request->session()->put('create_options', $publicKeyCredentialCreationOptions);
session(['create_options' => $options]);
return JsonResponse::fromJsonString($publicKeyCredentialCreationOptions);
return JsonResponse::fromJsonString($options);
}
/**
* @throws Throwable
* @throws WebauthnException
* @throws \JsonException
*/
public function create(Request $request): JsonResponse
{
/** @var User $user */
@ -126,17 +111,17 @@ class PasskeysController extends Controller
$publicKeyCredentialCreationOptionsData = session('create_options');
// Unset session data to mitigate replay attacks
$request->session()->forget('create_options');
session()->forget('create_options');
if (empty($publicKeyCredentialCreationOptionsData)) {
throw new WebAuthnException('No public key credential request options found');
}
$attestationStatementSupportManager = new AttestationStatementSupportManager;
$attestationStatementSupportManager->add(new NoneAttestationStatementSupport);
$webauthnSerializerFactory = new WebauthnSerializerFactory(
attestationStatementSupportManager: $attestationStatementSupportManager
);
$webauthnSerializer = $webauthnSerializerFactory->create();
$webauthnSerializer = (new WebauthnSerializerFactory(
$attestationStatementSupportManager
))->create();
$publicKeyCredential = $webauthnSerializer->deserialize(
json_encode($request->all(), JSON_THROW_ON_ERROR),
@ -161,11 +146,11 @@ class PasskeysController extends Controller
$ceremonyStepManagerFactory->setExtensionOutputCheckerHandler(
ExtensionOutputCheckerHandler::create()
);
$allowedOrigins = [];
$securedRelyingPartyId = [];
if (App::environment('local', 'development')) {
$allowedOrigins = [config('app.url')];
$securedRelyingPartyId = [config('url.longurl')];
}
$ceremonyStepManagerFactory->setAllowedOrigins($allowedOrigins);
$ceremonyStepManagerFactory->setSecuredRelyingPartyId($securedRelyingPartyId);
$authenticatorAttestationResponseValidator = AuthenticatorAttestationResponseValidator::create(
ceremonyStepManager: $ceremonyStepManagerFactory->creationCeremony()
@ -180,7 +165,8 @@ class PasskeysController extends Controller
$publicKeyCredentialSource = $authenticatorAttestationResponseValidator->check(
authenticatorAttestationResponse: $publicKeyCredential->response,
publicKeyCredentialCreationOptions: $publicKeyCredentialCreationOptions,
host: config('app.url')
request: config('url.longurl'),
securedRelyingPartyId: $securedRelyingPartyId,
);
$user->passkey()->create([
@ -194,37 +180,24 @@ class PasskeysController extends Controller
]);
}
/**
* @throws RandomException
* @throws \JsonException
*/
public function getRequestOptions(Request $request): JsonResponse
public function getRequestOptions(): JsonResponse
{
$publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions::create(
challenge: random_bytes(16),
userVerification: PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_REQUIRED
);
$attestationStatementSupportManager = AttestationStatementSupportManager::create();
$attestationStatementSupportManager->add(NoneAttestationStatementSupport::create());
$factory = new WebauthnSerializerFactory(
attestationStatementSupportManager: $attestationStatementSupportManager
);
$serializer = $factory->create();
$publicKeyCredentialRequestOptions = $serializer->serialize(data: $publicKeyCredentialRequestOptions, format: 'json');
$publicKeyCredentialRequestOptions = json_encode($publicKeyCredentialRequestOptions, JSON_THROW_ON_ERROR);
$request->session()->put('request_options', $publicKeyCredentialRequestOptions);
session(['request_options' => $publicKeyCredentialRequestOptions]);
return JsonResponse::fromJsonString($publicKeyCredentialRequestOptions);
}
/**
* @throws \JsonException
*/
public function login(Request $request): JsonResponse
{
$requestOptions = session('request_options');
$request->session()->forget('request_options');
session()->forget('request_options');
if (empty($requestOptions)) {
return response()->json([
@ -236,10 +209,9 @@ class PasskeysController extends Controller
$attestationStatementSupportManager = new AttestationStatementSupportManager;
$attestationStatementSupportManager->add(new NoneAttestationStatementSupport);
$webauthnSerializerFactory = new WebauthnSerializerFactory(
attestationStatementSupportManager: $attestationStatementSupportManager
);
$webauthnSerializer = $webauthnSerializerFactory->create();
$webauthnSerializer = (new WebauthnSerializerFactory(
$attestationStatementSupportManager
))->create();
$publicKeyCredential = $webauthnSerializer->deserialize(
json_encode($request->all(), JSON_THROW_ON_ERROR),
@ -284,11 +256,11 @@ class PasskeysController extends Controller
$ceremonyStepManagerFactory->setExtensionOutputCheckerHandler(
ExtensionOutputCheckerHandler::create()
);
$allowedOrigins = [];
$securedRelyingPartyId = [];
if (App::environment('local', 'development')) {
$allowedOrigins = [config('app.url')];
$securedRelyingPartyId = [config('url.longurl')];
}
$ceremonyStepManagerFactory->setAllowedOrigins($allowedOrigins);
$ceremonyStepManagerFactory->setSecuredRelyingPartyId($securedRelyingPartyId);
$authenticatorAssertionResponseValidator = AuthenticatorAssertionResponseValidator::create(
ceremonyStepManager: $ceremonyStepManagerFactory->requestCeremony()
@ -302,11 +274,12 @@ class PasskeysController extends Controller
try {
$authenticatorAssertionResponseValidator->check(
publicKeyCredentialSource: $publicKeyCredentialSource,
credentialId: $publicKeyCredentialSource,
authenticatorAssertionResponse: $publicKeyCredential->response,
publicKeyCredentialRequestOptions: $publicKeyCredentialRequestOptions,
host: config('app.url'),
request: config('url.longurl'),
userHandle: null,
securedRelyingPartyId: $securedRelyingPartyId,
);
} catch (Throwable) {
return response()->json([

View file

@ -10,6 +10,9 @@ use App\Services\PlaceService;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class PlacesController extends Controller
{
protected PlaceService $placeService;

View file

@ -10,6 +10,9 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class SyndicationTargetsController extends Controller
{
/**

View file

@ -10,6 +10,9 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
use Jonnybarnes\IndieWeb\Numbers;
/**
* @psalm-suppress UnusedClass
*/
class ArticlesController extends Controller
{
/**

View file

@ -9,6 +9,9 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class AuthController extends Controller
{
/**

View file

@ -7,6 +7,9 @@ namespace App\Http\Controllers;
use App\Models\Bookmark;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class BookmarksController extends Controller
{
/**

View file

@ -8,6 +8,9 @@ use App\Models\Contact;
use Illuminate\Filesystem\Filesystem;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class ContactsController extends Controller
{
/**

View file

@ -9,6 +9,9 @@ use App\Models\Note;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response;
/**
* @psalm-suppress UnusedClass
*/
class FeedsController extends Controller
{
/**
@ -119,8 +122,8 @@ class FeedsController extends Controller
foreach ($notes as $key => $note) {
$data['items'][$key] = [
'id' => $note->uri,
'url' => $note->uri,
'id' => $note->longurl,
'url' => $note->longurl,
'content_text' => $note->content,
'date_published' => $note->created_at->tz('UTC')->toRfc3339String(),
'date_modified' => $note->updated_at->tz('UTC')->toRfc3339String(),
@ -161,7 +164,7 @@ class FeedsController extends Controller
'author' => [
'type' => 'card',
'name' => config('user.display_name'),
'url' => config('app.url'),
'url' => config('url.longurl'),
],
'children' => $items,
], 200, [
@ -180,8 +183,8 @@ class FeedsController extends Controller
$items[] = [
'type' => 'entry',
'published' => $note->created_at,
'uid' => $note->uri,
'url' => $note->uri,
'uid' => $note->longurl,
'url' => $note->longurl,
'content' => [
'text' => $note->getRawOriginal('note'),
'html' => $note->note,
@ -197,7 +200,7 @@ class FeedsController extends Controller
'author' => [
'type' => 'card',
'name' => config('user.display_name'),
'url' => config('app.url'),
'url' => config('url.longurl'),
],
'children' => $items,
], 200, [

View file

@ -10,6 +10,9 @@ use App\Models\Note;
use Illuminate\Http\Response;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class FrontPageController extends Controller
{
/**

View file

@ -7,6 +7,9 @@ namespace App\Http\Controllers;
use App\Models\Like;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class LikesController extends Controller
{
/**

View file

@ -19,6 +19,9 @@ use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
/**
* @psalm-suppress UnusedClass
*/
class MicropubController extends Controller
{
protected TokenService $tokenService;

View file

@ -22,6 +22,9 @@ use Lcobucci\JWT\Token\InvalidTokenStructure;
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
use Ramsey\Uuid\Uuid;
/**
* @psalm-suppress UnusedClass
*/
class MicropubMediaController extends Controller
{
protected TokenService $tokenService;

View file

@ -14,6 +14,8 @@ use Jonnybarnes\IndieWeb\Numbers;
/**
* @todo Need to sort out Twitter and webmentions!
*
* @psalm-suppress UnusedClass
*/
class NotesController extends Controller
{

View file

@ -7,6 +7,9 @@ namespace App\Http\Controllers;
use App\Models\Place;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class PlacesController extends Controller
{
/**

View file

@ -6,6 +6,9 @@ use App\Models\Note;
use Illuminate\Http\Request;
use Illuminate\View\View;
/**
* @psalm-suppress UnusedClass
*/
class SearchController extends Controller
{
public function search(Request $request): View

View file

@ -0,0 +1,55 @@
<?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);
}
}

View file

@ -12,6 +12,9 @@ use Illuminate\Http\Response;
use Illuminate\View\View;
use Jonnybarnes\IndieWeb\Numbers;
/**
* @psalm-suppress UnusedClass
*/
class WebMentionsController extends Controller
{
/**

View file

@ -10,6 +10,8 @@ class CorsHeaders
{
/**
* Handle an incoming request.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function handle(Request $request, Closure $next): Response
{

View file

@ -10,6 +10,8 @@ class LinkHeadersMiddleware
{
/**
* Handle an incoming request.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function handle(Request $request, Closure $next): Response
{

View file

@ -14,6 +14,8 @@ class LocalhostSessionMiddleware
* Whilst we are developing locally, automatically log in as
* `['me' => config('app.url')]` as I cant manually log in as
* a .localhost domain.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function handle(Request $request, Closure $next): Response
{

View file

@ -13,6 +13,8 @@ class MyAuthMiddleware
{
/**
* Check the user is logged in.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function handle(Request $request, Closure $next): Response
{

View file

@ -10,6 +10,8 @@ class ValidateSignature extends Middleware
* The names of the query string parameters that should be ignored.
*
* @var array<int, string>
*
* @psalm-suppress PossiblyUnusedProperty
*/
protected $except = [
// 'fbclid',

View file

@ -12,6 +12,8 @@ class VerifyMicropubToken
{
/**
* Handle an incoming request.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function handle(Request $request, Closure $next): Response
{

View file

@ -53,7 +53,7 @@ class ProcessWebMention implements ShouldQueue
// check webmention still references target
// we try each type of mention (reply/like/repost)
if ($webmention->type === 'in-reply-to') {
if ($parser->checkInReplyTo($microformats, $this->note->uri) === false) {
if ($parser->checkInReplyTo($microformats, $this->note->longurl) === false) {
// it doesnt so delete
$webmention->delete();
@ -67,7 +67,7 @@ class ProcessWebMention implements ShouldQueue
return;
}
if ($webmention->type === 'like-of') {
if ($parser->checkLikeOf($microformats, $this->note->uri) === false) {
if ($parser->checkLikeOf($microformats, $this->note->longurl) === false) {
// it doesnt so delete
$webmention->delete();
@ -75,7 +75,7 @@ class ProcessWebMention implements ShouldQueue
} // note we dont need to do anything if it still is a like
}
if ($webmention->type === 'repost-of') {
if ($parser->checkRepostOf($microformats, $this->note->uri) === false) {
if ($parser->checkRepostOf($microformats, $this->note->longurl) === false) {
// it doesnt so delete
$webmention->delete();
@ -89,7 +89,7 @@ class ProcessWebMention implements ShouldQueue
$type = $parser->getMentionType($microformats); // throw error here?
dispatch(new SaveProfileImage($microformats));
$webmention->source = $this->source;
$webmention->target = $this->note->uri;
$webmention->target = $this->note->longurl;
$webmention->commentable_id = $this->note->id;
$webmention->commentable_type = Note::class;
$webmention->type = $type;

View file

@ -45,7 +45,7 @@ class SendWebMentions implements ShouldQueue
$guzzle = resolve(Client::class);
$guzzle->post($endpoint, [
'form_params' => [
'source' => $this->note->uri,
'source' => $this->note->longurl,
'target' => $url,
],
]);
@ -61,7 +61,7 @@ class SendWebMentions implements ShouldQueue
public function discoverWebmentionEndpoint(string $url): ?string
{
// lets not send webmentions to myself
if (parse_url($url, PHP_URL_HOST) === parse_url(config('app.url'), PHP_URL_HOST)) {
if (parse_url($url, PHP_URL_HOST) === config('url.longurl')) {
return null;
}
if (Str::startsWith($url, '/notes/tagged/')) {

View file

@ -26,7 +26,7 @@ class Bookmark extends Model
return $this->belongsToMany('App\Models\Tag');
}
protected function local_uri(): Attribute
protected function longurl(): Attribute
{
return Attribute::get(
get: fn () => config('app.url') . '/bookmarks/' . $this->id,

View file

@ -124,7 +124,7 @@ class Note extends Model
public function getNoteAttribute(?string $value): ?string
{
if ($value === null && $this->place !== null) {
$value = '📍: <a href="' . $this->place->uri . '">' . $this->place->name . '</a>';
$value = '📍: <a href="' . $this->place->longurl . '">' . $this->place->name . '</a>';
}
// if $value is still null, just return null
@ -172,11 +172,16 @@ class Note extends Model
return (string) resolve(Numbers::class)->numto60($this->id);
}
public function getUriAttribute(): string
public function getLongurlAttribute(): string
{
return config('app.url') . '/notes/' . $this->nb60id;
}
public function getShorturlAttribute(): string
{
return config('url.shorturl') . '/notes/' . $this->nb60id;
}
public function getIso8601Attribute(): string
{
return $this->updated_at->toISO8601String();

View file

@ -74,10 +74,24 @@ 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
{
return Attribute::get(
get: static fn ($value, $attributes) => config('app.url') . '/places/' . $attributes['slug'],
get: fn () => $this->longurl,
);
}

View file

@ -9,10 +9,15 @@ use App\Models\Tag;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
/**
* @todo Do we need psalm-suppress for these observer methods?
*/
class NoteObserver
{
/**
* Listen to the Note created event.=
* Listen to the Note created event.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function created(Note $note): void
{
@ -34,7 +39,9 @@ class NoteObserver
}
/**
* Listen to the Note updated event.=
* Listen to the Note updated event.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function updated(Note $note): void
{
@ -58,7 +65,9 @@ class NoteObserver
}
/**
* Listen to the Note deleting event.=
* Listen to the Note deleting event.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function deleting(Note $note): void
{

View file

@ -5,6 +5,9 @@ namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Laravel\Horizon\HorizonApplicationServiceProvider;
/**
* @psalm-suppress UnusedClass
*/
class HorizonServiceProvider extends HorizonApplicationServiceProvider
{
/**

View file

@ -27,6 +27,6 @@ class HCardService
$data['longitude'] = Arr::get($request, 'longitude');
}
return resolve(PlaceService::class)->createPlace($data)->uri;
return resolve(PlaceService::class)->createPlace($data)->longurl;
}
}

View file

@ -18,17 +18,17 @@ class HEntryService
public function process(array $request, ?string $client = null): ?string
{
if (Arr::get($request, 'properties.like-of') || Arr::get($request, 'like-of')) {
return resolve(LikeService::class)->create($request)->url;
return resolve(LikeService::class)->create($request)->longurl;
}
if (Arr::get($request, 'properties.bookmark-of') || Arr::get($request, 'bookmark-of')) {
return resolve(BookmarkService::class)->create($request)->uri;
return resolve(BookmarkService::class)->create($request)->longurl;
}
if (Arr::get($request, 'properties.name') || Arr::get($request, 'name')) {
return resolve(ArticleService::class)->create($request)->link;
return resolve(ArticleService::class)->create($request)->longurl;
}
return resolve(NoteService::class)->create($request, $client)->uri;
return resolve(NoteService::class)->create($request, $client)->longurl;
}
}

32
config/url.php Normal file
View file

@ -0,0 +1,32 @@
<?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'),
];

View file

@ -7,6 +7,8 @@ use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Carbon;
/**
* @psalm-suppress UnusedClass
*
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Article>
*/
class ArticleFactory extends Factory

View file

@ -5,6 +5,8 @@ namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @psalm-suppress UnusedClass
*
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Bio>
*/
class BioFactory extends Factory

View file

@ -7,6 +7,8 @@ use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Carbon;
/**
* @psalm-suppress UnusedClass
*
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Bookmark>
*/
class BookmarkFactory extends Factory

View file

@ -7,6 +7,8 @@ use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Carbon;
/**
* @psalm-suppress UnusedClass
*
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Contact>
*/
class ContactFactory extends Factory

View file

@ -7,6 +7,8 @@ use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Carbon;
/**
* @psalm-suppress UnusedClass
*
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Like>
*/
class LikeFactory extends Factory

View file

@ -7,6 +7,8 @@ use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Carbon;
/**
* @psalm-suppress UnusedClass
*
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Media>
*/
class MediaFactory extends Factory

View file

@ -6,6 +6,8 @@ use App\Models\MicropubClient;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @psalm-suppress UnusedClass
*
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\MicropubClient>
*/
class MicropubClientFactory extends Factory

View file

@ -8,6 +8,8 @@ use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Carbon;
/**
* @psalm-suppress UnusedClass
*
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Note>
*/
class NoteFactory extends Factory

View file

@ -6,6 +6,8 @@ use App\Models\Place;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @psalm-suppress UnusedClass
*
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Place>
*/
class PlaceFactory extends Factory

View file

@ -5,6 +5,8 @@ namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @psalm-suppress UnusedClass
*
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\SyndicationTarget>
*/
class SyndicationTargetFactory extends Factory

View file

@ -6,6 +6,8 @@ use App\Models\Tag;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @psalm-suppress UnusedClass
*
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Tag>
*/
class TagFactory extends Factory

View file

@ -7,6 +7,8 @@ use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
/**
* @psalm-suppress UnusedClass
*
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
*/
class UserFactory extends Factory

View file

@ -6,6 +6,8 @@ use App\Models\WebMention;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @psalm-suppress UnusedClass
*
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\WebMention>
*/
class WebMentionFactory extends Factory

View file

@ -11,6 +11,8 @@ class ArticlesTableSeeder extends Seeder
{
/**
* Seed the articles table.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function run(): void
{

View file

@ -5,6 +5,9 @@ namespace Database\Seeders;
use App\Models\Bio;
use Illuminate\Database\Seeder;
/**
* @psalm-suppress UnusedClass
*/
class BioSeeder extends Seeder
{
/**

View file

@ -10,6 +10,8 @@ class BookmarksTableSeeder extends Seeder
{
/**
* Seed the bookmarks table.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function run(): void
{

View file

@ -11,6 +11,8 @@ class ClientsTableSeeder extends Seeder
{
/**
* Seed the clients table.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function run(): void
{

View file

@ -10,6 +10,8 @@ class ContactsTableSeeder extends Seeder
{
/**
* Seed the contacts table.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function run(): void
{

View file

@ -4,6 +4,9 @@ namespace Database\Seeders;
use Illuminate\Database\Seeder;
/**
* @psalm-suppress UnusedClass
*/
class DatabaseSeeder extends Seeder
{
/**

View file

@ -12,6 +12,8 @@ class LikesTableSeeder extends Seeder
{
/**
* Seed the likes table.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function run(): void
{

View file

@ -14,6 +14,8 @@ class NotesTableSeeder extends Seeder
{
/**
* Seed the notes table.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function run(): void
{

View file

@ -9,6 +9,8 @@ class PlacesTableSeeder extends Seeder
{
/**
* Seed the places table.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function run(): void
{

View file

@ -9,6 +9,8 @@ class UsersTableSeeder extends Seeder
{
/**
* Seed the users table.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function run(): void
{

View file

@ -9,6 +9,8 @@ class WebMentionsTableSeeder extends Seeder
{
/**
* Seed the webmentions table.
*
* @psalm-suppress PossiblyUnusedMethod
*/
public function run(): void
{

1347
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -7,23 +7,21 @@
"license": "CC0-1.0",
"devDependencies": {
"@eslint/js": "^9.6.0",
"@stylistic/eslint-plugin": "^4.2.0",
"esbuild": "^0.25.2",
"@stylistic/eslint-plugin": "^3.0.0",
"eslint": "^9.7.0",
"globals": "^16.0.0",
"lightningcss": "^1.29.3",
"lightningcss-cli": "^1.29.3",
"globals": "^15.8.0",
"stylelint": "^16.7.0",
"stylelint-config-standard": "^38.0.0"
"stylelint-config-standard": "^37.0.0"
},
"scripts": {
"eslint": "eslint public/assets/js/*.js",
"stylelint": "stylelint resources/css/*.css",
"stylelint": "stylelint public/assets/css/*.css",
"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",
"build": "npm run lint && npm run compress"
},
"dependencies": {
"@11ty/is-land": "^4.0.0",
"@zachleat/snow-fall": "^1.0.2"
}
}

16
postcss.config.js Normal file
View file

@ -0,0 +1,16 @@
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 Normal file
View file

@ -0,0 +1,18 @@
<?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>

View file

@ -1,2 +1,8 @@
: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}}
/*# sourceMappingURL=/assets/css/app.css.map */
@import url('variables.css');
@import url('fonts.css');
@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.

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.

Some files were not shown because too many files have changed in this diff Show more