Merge branch 'develop' into github-action-deploy
This commit is contained in:
commit
005d3cdf90
87 changed files with 8359 additions and 11741 deletions
|
|
@ -7,7 +7,7 @@ APP_LOG_LEVEL=warning
|
|||
DB_CONNECTION=pgsql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=5432
|
||||
DB_DATABASE=jbuktest
|
||||
DB_DATABASE=jbukdev_testing
|
||||
DB_USERNAME=postgres
|
||||
DB_PASSWORD=postgres
|
||||
|
||||
|
|
|
|||
17
.env.travis
17
.env.travis
|
|
@ -1,17 +0,0 @@
|
|||
APP_ENV=testing
|
||||
APP_DEBUG=true
|
||||
APP_KEY=base64:6DJhvZLVjE6dD4Cqrteh+6Z5vZlG+v/soCKcDHLOAH0=
|
||||
APP_URL=http://jonnybarnes.localhost
|
||||
APP_LONGURL=jonnybarnes.localhost
|
||||
APP_SHORTURL=jmb.localhost
|
||||
|
||||
DB_CONNECTION=travis
|
||||
|
||||
CACHE_DRIVER=array
|
||||
SESSION_DRIVER=array
|
||||
QUEUE_DRIVER=sync
|
||||
|
||||
SCOUT_DRIVER=pgsql
|
||||
|
||||
DISPLAY_NAME='Travis Test'
|
||||
USER_NAME=travis
|
||||
10
.github/workflows/run-tests.yml
vendored
10
.github/workflows/run-tests.yml
vendored
|
|
@ -11,11 +11,11 @@ jobs:
|
|||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:13.1
|
||||
image: postgres:13.4
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: jbuktest
|
||||
POSTGRES_DB: jbukdev_testing
|
||||
ports:
|
||||
- 5432:5432
|
||||
|
||||
|
|
@ -36,15 +36,13 @@ jobs:
|
|||
- name: Copy .env
|
||||
run: php -r "file_exists('.env') || copy('.env.github', '.env');"
|
||||
- name: Install dependencies
|
||||
run: composer install -q --no-ansi --no-interaction --no-progress
|
||||
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 test database
|
||||
run: |
|
||||
php artisan migrate
|
||||
php artisan db:seed
|
||||
run: php artisan migrate
|
||||
- name: Execute tests (Unit and Feature tests) via PHPUnit
|
||||
run: vendor/bin/phpunit
|
||||
- name: Run phpcs
|
||||
|
|
|
|||
|
|
@ -24,16 +24,6 @@ class ParseCachedWebMentions extends Command
|
|||
*/
|
||||
protected $description = 'Re-parse the webmention’s cached HTML';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
|
|
@ -41,15 +31,15 @@ class ParseCachedWebMentions extends Command
|
|||
*/
|
||||
public function handle(FileSystem $filesystem)
|
||||
{
|
||||
$HTMLfiles = $filesystem->allFiles(storage_path() . '/HTML');
|
||||
foreach ($HTMLfiles as $file) {
|
||||
if ($file->getExtension() != 'backup') { //we don’t want to parse.backup files
|
||||
$htmlFiles = $filesystem->allFiles(storage_path() . '/HTML');
|
||||
foreach ($htmlFiles as $file) {
|
||||
if ($file->getExtension() !== 'backup') { //we don’t want to parse `.backup` files
|
||||
$filepath = $file->getPathname();
|
||||
$this->info('Loading HTML from: ' . $filepath);
|
||||
$html = $filesystem->get($filepath);
|
||||
$url = $this->URLFromFilename($filepath);
|
||||
$microformats = \Mf2\parse($html, $url);
|
||||
$url = $this->urlFromFilename($filepath);
|
||||
$webmention = WebMention::where('source', $url)->firstOrFail();
|
||||
$microformats = \Mf2\parse($html, $url);
|
||||
$webmention->mf2 = json_encode($microformats);
|
||||
$webmention->save();
|
||||
$this->info('Saved the microformats to the database.');
|
||||
|
|
@ -63,12 +53,12 @@ class ParseCachedWebMentions extends Command
|
|||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
private function URLFromFilename(string $filepath): string
|
||||
private function urlFromFilename(string $filepath): string
|
||||
{
|
||||
$dir = mb_substr($filepath, mb_strlen(storage_path() . '/HTML/'));
|
||||
$url = str_replace(['http/', 'https/'], ['http://', 'https://'], $dir);
|
||||
if (mb_substr($url, -10) == 'index.html') {
|
||||
$url = mb_substr($url, 0, mb_strlen($url) - 10);
|
||||
if (mb_substr($url, -10) === 'index.html') {
|
||||
$url = mb_substr($url, 0, -10);
|
||||
}
|
||||
|
||||
return $url;
|
||||
|
|
|
|||
|
|
@ -7,16 +7,10 @@ namespace App\Http\Controllers\Admin;
|
|||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Article;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class ArticlesController extends Controller
|
||||
{
|
||||
/**
|
||||
* List the articles that can be edited.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
$posts = Article::select('id', 'title', 'published')->orderBy('id', 'desc')->get();
|
||||
|
|
@ -24,11 +18,6 @@ class ArticlesController extends Controller
|
|||
return view('admin.articles.index', ['posts' => $posts]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the new article form.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
$message = session('message');
|
||||
|
|
@ -36,11 +25,6 @@ class ArticlesController extends Controller
|
|||
return view('admin.articles.create', ['message' => $message]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an incoming request for a new article and save it.
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function store(): RedirectResponse
|
||||
{
|
||||
//if a `.md` is attached use that for the main content.
|
||||
|
|
@ -49,42 +33,21 @@ class ArticlesController extends Controller
|
|||
$content = $file->fread($file->getSize());
|
||||
}
|
||||
$main = $content ?? request()->input('main');
|
||||
$article = Article::create(
|
||||
[
|
||||
'url' => request()->input('url'),
|
||||
'title' => request()->input('title'),
|
||||
'main' => $main,
|
||||
'published' => request()->input('published') ?? 0,
|
||||
]
|
||||
);
|
||||
Article::create([
|
||||
'url' => request()->input('url'),
|
||||
'title' => request()->input('title'),
|
||||
'main' => $main,
|
||||
'published' => request()->input('published') ?? 0,
|
||||
]);
|
||||
|
||||
return redirect('/admin/blog');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the edit form for an existing article.
|
||||
*
|
||||
* @param int $articleId
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit(int $articleId): View
|
||||
public function edit(Article $article): View
|
||||
{
|
||||
$post = Article::select(
|
||||
'title',
|
||||
'main',
|
||||
'url',
|
||||
'published'
|
||||
)->where('id', $articleId)->get();
|
||||
|
||||
return view('admin.articles.edit', ['id' => $articleId, 'post' => $post]);
|
||||
return view('admin.articles.edit', ['article' => $article]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an incoming request to edit an article.
|
||||
*
|
||||
* @param int $articleId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(int $articleId): RedirectResponse
|
||||
{
|
||||
$article = Article::find($articleId);
|
||||
|
|
@ -97,12 +60,6 @@ class ArticlesController extends Controller
|
|||
return redirect('/admin/blog');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a request to delete an aricle.
|
||||
*
|
||||
* @param int $articleId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function destroy(int $articleId): RedirectResponse
|
||||
{
|
||||
Article::where('id', $articleId)->delete();
|
||||
|
|
|
|||
|
|
@ -59,18 +59,14 @@ class ArticlesController extends Controller
|
|||
* We only have the ID, work out post title, year and month
|
||||
* and redirect to it.
|
||||
*
|
||||
* @param int $idFromUrl
|
||||
* @param string $idFromUrl
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function onlyIdInUrl(int $idFromUrl): RedirectResponse
|
||||
public function onlyIdInUrl(string $idFromUrl): RedirectResponse
|
||||
{
|
||||
$realId = resolve(Numbers::class)->b60tonum((string) $idFromUrl);
|
||||
$realId = resolve(Numbers::class)->b60tonum($idFromUrl);
|
||||
|
||||
try {
|
||||
$article = Article::findOrFail($realId);
|
||||
} catch (ModelNotFoundException $exception) {
|
||||
abort(404);
|
||||
}
|
||||
$article = Article::findOrFail($realId);
|
||||
|
||||
return redirect($article->link);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,19 +18,15 @@ class CSPHeader
|
|||
{
|
||||
// headers have to be single-line strings,
|
||||
// so we concat multiple lines
|
||||
// phpcs:disable
|
||||
// phpcs:disable Generic.Files.LineLength.TooLong
|
||||
return $next($request)
|
||||
->header(
|
||||
'Content-Security-Policy',
|
||||
"default-src 'self'; " .
|
||||
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://api.mapbox.com https://api.tiles.mapbox.com blob:; " .
|
||||
"style-src 'self' 'unsafe-inline' https://api.mapbox.com https://api.tiles.mapbox.com cloud.typography.com jonnybarnes.uk; " .
|
||||
"img-src 'self' data: blob: https://pbs.twimg.com https://api.mapbox.com https://*.tiles.mapbox.com https://jbuk-media.s3-eu-west-1.amazonaws.com https://jbuk-media-dev.s3-eu-west-1.amazonaws.com https://secure.gravatar.com https://graph.facebook.com *.fbcdn.net https://*.cdninstagram.com https://*.4sqi.net https://upload.wikimedia.org; " .
|
||||
"style-src 'self' cloud.typography.com jonnybarnes.uk; " .
|
||||
"img-src 'self' data: blob: https://pbs.twimg.com https://jbuk-media.s3-eu-west-1.amazonaws.com https://jbuk-media-dev.s3-eu-west-1.amazonaws.com https://secure.gravatar.com https://graph.facebook.com *.fbcdn.net https://*.cdninstagram.com https://*.4sqi.net https://upload.wikimedia.org; " .
|
||||
"font-src 'self' data:; " .
|
||||
"connect-src 'self' https://api.mapbox.com https://*.tiles.mapbox.com https://events.mapbox.com data: blob:; " .
|
||||
"worker-src 'self' blob:; " .
|
||||
"frame-src 'self' https://www.youtube.com blob:; " .
|
||||
'child-src blob:; ' .
|
||||
'upgrade-insecure-requests; ' .
|
||||
'block-all-mixed-content; ' .
|
||||
'report-to csp-endpoint; ' .
|
||||
|
|
@ -43,6 +39,6 @@ class CSPHeader
|
|||
"'max-age': 10886400" .
|
||||
'}'
|
||||
);
|
||||
// phpcs:enable
|
||||
// phpcs:enable Generic.Files.LineLength.TooLong
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,11 +41,13 @@ class SaveProfileImage implements ShouldQueue
|
|||
{
|
||||
try {
|
||||
$author = $authorship->findAuthor($this->microformats);
|
||||
} catch (AuthorshipParserException $e) {
|
||||
return;
|
||||
} catch (AuthorshipParserException) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$photo = Arr::get($author, 'properties.photo.0');
|
||||
$home = Arr::get($author, 'properties.url.0');
|
||||
|
||||
//dont save pbs.twimg.com links
|
||||
if (
|
||||
$photo
|
||||
|
|
@ -53,16 +55,18 @@ class SaveProfileImage implements ShouldQueue
|
|||
&& parse_url($photo, PHP_URL_HOST) != 'twitter.com'
|
||||
) {
|
||||
$client = resolve(Client::class);
|
||||
|
||||
try {
|
||||
$response = $client->get($photo);
|
||||
$image = $response->getBody();
|
||||
} catch (RequestException $e) {
|
||||
} catch (RequestException) {
|
||||
// we are opening and reading the default image so that
|
||||
$default = public_path() . '/assets/profile-images/default-image';
|
||||
$handle = fopen($default, 'rb');
|
||||
$image = fread($handle, filesize($default));
|
||||
fclose($handle);
|
||||
}
|
||||
|
||||
$path = public_path() . '/assets/profile-images/' . parse_url($home, PHP_URL_HOST) . '/image';
|
||||
$parts = explode('/', $path);
|
||||
$name = array_pop($parts);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ namespace App\Jobs;
|
|||
|
||||
use App\Models\Note;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Psr7\Header;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use GuzzleHttp\Psr7\UriResolver;
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
|
@ -65,14 +68,14 @@ class SendWebMentions implements ShouldQueue
|
|||
* @param string $url
|
||||
* @return string|null
|
||||
*/
|
||||
public function discoverWebmentionEndpoint(string $url)
|
||||
public function discoverWebmentionEndpoint(string $url): ?string
|
||||
{
|
||||
//let’s not send webmentions to myself
|
||||
if (parse_url($url, PHP_URL_HOST) == config('app.longurl')) {
|
||||
return;
|
||||
if (parse_url($url, PHP_URL_HOST) === config('app.longurl')) {
|
||||
return null;
|
||||
}
|
||||
if (Str::startsWith($url, '/notes/tagged/')) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$endpoint = null;
|
||||
|
|
@ -80,7 +83,7 @@ class SendWebMentions implements ShouldQueue
|
|||
$guzzle = resolve(Client::class);
|
||||
$response = $guzzle->get($url);
|
||||
//check HTTP Headers for webmention endpoint
|
||||
$links = \GuzzleHttp\Psr7\parse_header($response->getHeader('Link'));
|
||||
$links = Header::parse($response->getHeader('Link'));
|
||||
foreach ($links as $link) {
|
||||
if (mb_stristr($link['rel'], 'webmention')) {
|
||||
return $this->resolveUri(trim($link[0], '<>'), $url);
|
||||
|
|
@ -110,7 +113,7 @@ class SendWebMentions implements ShouldQueue
|
|||
*/
|
||||
public function getLinks(?string $html): array
|
||||
{
|
||||
if ($html == '' || is_null($html)) {
|
||||
if ($html === '' || is_null($html)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
|
@ -136,13 +139,13 @@ class SendWebMentions implements ShouldQueue
|
|||
*/
|
||||
public function resolveUri(string $url, string $base): string
|
||||
{
|
||||
$endpoint = \GuzzleHttp\Psr7\uri_for($url);
|
||||
if ($endpoint->getScheme() != '') {
|
||||
$endpoint = Utils::uriFor($url);
|
||||
if ($endpoint->getScheme() !== '') {
|
||||
return (string) $endpoint;
|
||||
}
|
||||
|
||||
return (string) Uri::resolve(
|
||||
\GuzzleHttp\Psr7\uri_for($base),
|
||||
return (string) UriResolver::resolve(
|
||||
Utils::uriFor($base),
|
||||
$endpoint
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ namespace App\Models;
|
|||
use Cviebrock\EloquentSluggable\Sluggable;
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
|
@ -58,6 +59,7 @@ use Spatie\CommonMarkHighlighter\IndentedCodeRenderer;
|
|||
*/
|
||||
class Article extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Sluggable;
|
||||
use SoftDeletes;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ namespace App\Models;
|
|||
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
|
|
@ -35,6 +36,8 @@ use Illuminate\Support\Carbon;
|
|||
*/
|
||||
class Contact extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The database table used by the model.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ namespace App\Models;
|
|||
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
|
@ -41,6 +42,8 @@ use Illuminate\Support\Str;
|
|||
*/
|
||||
class Media extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
|
|
@ -62,7 +65,7 @@ class Media extends Model
|
|||
*/
|
||||
public function note(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo('App\Models\Note');
|
||||
return $this->belongsTo(Note::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -118,7 +121,7 @@ class Media extends Model
|
|||
$filenameParts = explode('.', $path);
|
||||
array_pop($filenameParts);
|
||||
|
||||
return ltrim(array_reduce($filenameParts, function ($carry, $item) {
|
||||
return ltrim(array_reduce($filenameParts, static function ($carry, $item) {
|
||||
return $carry . '.' . $item;
|
||||
}, ''), '.');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,15 @@ declare(strict_types=1);
|
|||
namespace App\Models;
|
||||
|
||||
use App\Exceptions\TwitterContentException;
|
||||
use Barryvdh\LaravelIdeHelper\Eloquent;
|
||||
use Codebird\Codebird;
|
||||
use Eloquent;
|
||||
use Exception;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Database\Eloquent\Relations\{BelongsTo, BelongsToMany, HasMany, MorphMany};
|
||||
use Illuminate\Database\Eloquent\{Builder, Collection, Factories\HasFactory, Model, SoftDeletes};
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use Jonnybarnes\IndieWeb\Numbers;
|
||||
use Laravel\Scout\Searchable;
|
||||
use League\CommonMark\Block\Element\{FencedCode, IndentedCode};
|
||||
|
|
@ -20,6 +21,11 @@ use League\CommonMark\Extension\Autolink\AutolinkExtension;
|
|||
use League\CommonMark\{CommonMarkConverter, Environment};
|
||||
use Normalizer;
|
||||
use Spatie\CommonMarkHighlighter\{FencedCodeRenderer, IndentedCodeRenderer};
|
||||
use App\Models\Tag;
|
||||
use App\Models\MicropubClient;
|
||||
use App\Models\WebMention;
|
||||
use App\Models\Place;
|
||||
use App\Models\Media;
|
||||
|
||||
/**
|
||||
* App\Models\Note.
|
||||
|
|
@ -102,12 +108,12 @@ class Note extends Model
|
|||
/**
|
||||
* This variable is used to keep track of contacts in a note.
|
||||
*/
|
||||
protected $contacts;
|
||||
protected ?array $contacts;
|
||||
|
||||
/**
|
||||
* Set our contacts variable to null.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param array $attributes
|
||||
*/
|
||||
public function __construct(array $attributes = [])
|
||||
{
|
||||
|
|
@ -145,9 +151,9 @@ class Note extends Model
|
|||
*
|
||||
* @return BelongsToMany
|
||||
*/
|
||||
public function tags()
|
||||
public function tags(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany('App\Models\Tag');
|
||||
return $this->belongsToMany(Tag::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -155,9 +161,9 @@ class Note extends Model
|
|||
*
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function client()
|
||||
public function client(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo('App\Models\MicropubClient', 'client_id', 'client_url');
|
||||
return $this->belongsTo(MicropubClient::class, 'client_id', 'client_url');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -165,9 +171,9 @@ class Note extends Model
|
|||
*
|
||||
* @return MorphMany
|
||||
*/
|
||||
public function webmentions()
|
||||
public function webmentions(): MorphMany
|
||||
{
|
||||
return $this->morphMany('App\Models\WebMention', 'commentable');
|
||||
return $this->morphMany(WebMention::class, 'commentable');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -175,9 +181,9 @@ class Note extends Model
|
|||
*
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function place()
|
||||
public function place(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo('App\Models\Place');
|
||||
return $this->belongsTo(Place::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -185,9 +191,9 @@ class Note extends Model
|
|||
*
|
||||
* @return HasMany
|
||||
*/
|
||||
public function media()
|
||||
public function media(): HasMany
|
||||
{
|
||||
return $this->hasMany('App\Models\Media');
|
||||
return $this->hasMany(Media::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -195,6 +201,7 @@ class Note extends Model
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
#[ArrayShape(['note' => "null|string"])]
|
||||
public function toSearchableArray(): array
|
||||
{
|
||||
return [
|
||||
|
|
@ -207,7 +214,7 @@ class Note extends Model
|
|||
*
|
||||
* @param string|null $value
|
||||
*/
|
||||
public function setNoteAttribute(?string $value)
|
||||
public function setNoteAttribute(?string $value): void
|
||||
{
|
||||
if ($value !== null) {
|
||||
$normalized = normalizer_normalize($value, Normalizer::FORM_C);
|
||||
|
|
@ -253,13 +260,13 @@ class Note extends Model
|
|||
$note = $this->note;
|
||||
|
||||
foreach ($this->media as $media) {
|
||||
if ($media->type == 'image') {
|
||||
if ($media->type === 'image') {
|
||||
$note .= '<img src="' . $media->url . '" alt="">';
|
||||
}
|
||||
if ($media->type == 'audio') {
|
||||
if ($media->type === 'audio') {
|
||||
$note .= '<audio src="' . $media->url . '">';
|
||||
}
|
||||
if ($media->type == 'video') {
|
||||
if ($media->type === 'video') {
|
||||
$note .= '<video src="' . $media->url . '">';
|
||||
}
|
||||
}
|
||||
|
|
@ -398,7 +405,10 @@ class Note extends Model
|
|||
*/
|
||||
public function getTwitterAttribute(): ?object
|
||||
{
|
||||
if ($this->in_reply_to == null || mb_substr($this->in_reply_to, 0, 20, 'UTF-8') !== 'https://twitter.com/') {
|
||||
if (
|
||||
$this->in_reply_to === null ||
|
||||
!$this->isTwitterLink($this->in_reply_to)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -569,7 +579,7 @@ class Note extends Model
|
|||
public function autoLinkHashtag(string $note): string
|
||||
{
|
||||
return preg_replace_callback(
|
||||
'/#([^\s]*)\b/',
|
||||
'/#([^\s[:punct:]]+)/',
|
||||
function ($matches) {
|
||||
return '<a rel="tag" class="p-category" href="/notes/tagged/'
|
||||
. Tag::normalize($matches[1]) . '">#'
|
||||
|
|
@ -660,4 +670,9 @@ class Note extends Model
|
|||
return $address;
|
||||
});
|
||||
}
|
||||
|
||||
private function isTwitterLink(string $inReplyTo): bool
|
||||
{
|
||||
return str_starts_with($inReplyTo, 'https://twitter.com/');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* App\Models\Tag.
|
||||
|
|
@ -50,7 +51,7 @@ class Tag extends Model
|
|||
*/
|
||||
public function notes()
|
||||
{
|
||||
return $this->belongsToMany('App\Models\Note');
|
||||
return $this->belongsToMany(Note::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -82,13 +83,6 @@ class Tag extends Model
|
|||
*/
|
||||
public static function normalize(string $tag): string
|
||||
{
|
||||
return mb_strtolower(
|
||||
preg_replace(
|
||||
'/&([a-z]{1,2})(acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml|caron);/i',
|
||||
'$1',
|
||||
htmlentities($tag)
|
||||
),
|
||||
'UTF-8'
|
||||
);
|
||||
return Str::slug($tag);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use App\Traits\FilterHtml;
|
|||
use Codebird\Codebird;
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
|
|
@ -55,6 +56,7 @@ use Jonnybarnes\WebmentionsParser\Exceptions\AuthorshipParserException;
|
|||
class WebMention extends Model
|
||||
{
|
||||
use FilterHtml;
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The database table used by the model.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
],
|
||||
"license": "CC0-1.0",
|
||||
"require": {
|
||||
"php": "^7.4|^8.0",
|
||||
"php": "^8.0",
|
||||
"ext-intl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-dom": "*",
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
"league/commonmark": "^1.0",
|
||||
"league/flysystem-aws-s3-v3": "^1.0",
|
||||
"mf2/mf2": "~0.3",
|
||||
"pmatseykanets/laravel-scout-postgres": "dev-php8",
|
||||
"pmatseykanets/laravel-scout-postgres": "^7.3",
|
||||
"predis/predis": "~1.0",
|
||||
"spatie/browsershot": "~3.0",
|
||||
"spatie/commonmark-highlighter": "^2.0",
|
||||
|
|
@ -48,6 +48,7 @@
|
|||
"nunomaduro/collision": "^5.0",
|
||||
"phpunit/php-code-coverage": "^9.2",
|
||||
"phpunit/phpunit": "^9.0",
|
||||
"spatie/laravel-ray": "^1.12",
|
||||
"vimeo/psalm": "^4.0"
|
||||
},
|
||||
"config": {
|
||||
|
|
@ -91,11 +92,5 @@
|
|||
"test": [
|
||||
"vendor/bin/phpunit --stop-on-failure"
|
||||
]
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/jonnybarnes/laravel-scout-postgres"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
3064
composer.lock
generated
3064
composer.lock
generated
File diff suppressed because it is too large
Load diff
34
database/factories/ArticleFactory.php
Normal file
34
database/factories/ArticleFactory.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Article;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class ArticleFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Article::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'titleurl' => $this->faker->slug(3),
|
||||
'title' => $this->faker->words(3, true),
|
||||
'main' => $this->faker->paragraphs(4, true),
|
||||
'published' => 1,
|
||||
'created_at' => Carbon::now()->toDateTimeString(),
|
||||
'updated_at' => Carbon::now()->toDateTimeString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
35
database/factories/ContactFactory.php
Normal file
35
database/factories/ContactFactory.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Contact;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class ContactFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Contact::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'nick' => mb_strtolower($this->faker->firstName),
|
||||
'name' => $this->faker->name(),
|
||||
'homepage' => $this->faker->url,
|
||||
'twitter' => mb_strtolower($this->faker->firstName),
|
||||
'facebook' => $this->faker->randomNumber(5),
|
||||
'created_at' => Carbon::now()->toDateTimeString(),
|
||||
'updated_at' => Carbon::now()->toDateTimeString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
32
database/factories/MediaFactory.php
Normal file
32
database/factories/MediaFactory.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Media;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class MediaFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Media::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'path' => 'media/' . $this->faker->uuid . '.jpg',
|
||||
'type' => 'image',
|
||||
'created_at' => Carbon::now()->toDateTimeString(),
|
||||
'updated_at' => Carbon::now()->toDateTimeString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue