Upgrade to Laravel 13
This commit is contained in:
parent
e8e2bff5e4
commit
9f012b01e4
117 changed files with 1878 additions and 2215 deletions
|
|
@ -28,10 +28,10 @@ class MentionRenderer implements NodeRendererInterface
|
|||
|
||||
// This is not [@]handle@instance, so return a Twitter link
|
||||
if (count($parts) === 1) {
|
||||
return new HtmlElement('a', ['href' => 'https://twitter.com/' . $parts[0]], '@' . $mentionText);
|
||||
return new HtmlElement('a', ['href' => 'https://twitter.com/'.$parts[0]], '@'.$mentionText);
|
||||
}
|
||||
|
||||
// Render the Mastodon profile link
|
||||
return new HtmlElement('a', ['href' => 'https://' . $parts[1] . '/@' . $parts[0]], '@' . $mentionText);
|
||||
return new HtmlElement('a', ['href' => 'https://'.$parts[1].'/@'.$parts[0]], '@'.$mentionText);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,10 +34,10 @@ class CopyMediaToLocal extends Command
|
|||
foreach ($media as $mediaItem) {
|
||||
$filename = $mediaItem->path;
|
||||
|
||||
$this->info('Processing: ' . $filename);
|
||||
$this->info('Processing: '.$filename);
|
||||
|
||||
// If the file is already saved locally skip to next one
|
||||
if (Storage::disk('local')->exists('public/' . $filename)) {
|
||||
if (Storage::disk('local')->exists('public/'.$filename)) {
|
||||
$this->info('File already exists locally, skipping');
|
||||
|
||||
continue;
|
||||
|
|
@ -50,19 +50,19 @@ class CopyMediaToLocal extends Command
|
|||
continue;
|
||||
}
|
||||
$contents = Storage::disk('s3')->get($filename);
|
||||
Storage::disk('local')->put('public/' . $filename, $contents);
|
||||
Storage::disk('local')->put('public/'.$filename, $contents);
|
||||
|
||||
// Copy -medium and -small versions if they exist
|
||||
$filenameParts = explode('.', $filename);
|
||||
$extension = array_pop($filenameParts);
|
||||
$basename = trim(implode('.', $filenameParts), '.');
|
||||
$mediumFilename = $basename . '-medium.' . $extension;
|
||||
$smallFilename = $basename . '-small.' . $extension;
|
||||
$mediumFilename = $basename.'-medium.'.$extension;
|
||||
$smallFilename = $basename.'-small.'.$extension;
|
||||
if (Storage::disk('s3')->exists($mediumFilename)) {
|
||||
Storage::disk('local')->put('public/' . $mediumFilename, Storage::disk('s3')->get($mediumFilename));
|
||||
Storage::disk('local')->put('public/'.$mediumFilename, Storage::disk('s3')->get($mediumFilename));
|
||||
}
|
||||
if (Storage::disk('s3')->exists($smallFilename)) {
|
||||
Storage::disk('local')->put('public/' . $smallFilename, Storage::disk('s3')->get($smallFilename));
|
||||
Storage::disk('local')->put('public/'.$smallFilename, Storage::disk('s3')->get($smallFilename));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ class MigratePlaceDataFromPostgis extends Command
|
|||
$places = Place::all();
|
||||
|
||||
$places->each(function ($place) {
|
||||
$this->info('Extracting Postgis data for place: ' . $place->name);
|
||||
$this->info('Extracting Postgis data for place: '.$place->name);
|
||||
|
||||
$place->latitude = $place->location->getLat();
|
||||
$place->longitude = $place->location->getLng();
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@ class ParseCachedWebMentions extends Command
|
|||
*/
|
||||
public function handle(FileSystem $filesystem): void
|
||||
{
|
||||
$htmlFiles = $filesystem->allFiles(storage_path() . '/HTML');
|
||||
$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);
|
||||
$this->info('Loading HTML from: '.$filepath);
|
||||
$html = $filesystem->get($filepath);
|
||||
$url = $this->urlFromFilename($filepath);
|
||||
$webmention = WebMention::where('source', $url)->firstOrFail();
|
||||
|
|
@ -53,7 +53,7 @@ class ParseCachedWebMentions extends Command
|
|||
*/
|
||||
private function urlFromFilename(string $filepath): string
|
||||
{
|
||||
$dir = mb_substr($filepath, mb_strlen(storage_path() . '/HTML/'));
|
||||
$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, -10);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class ReDownloadWebMentions extends Command
|
|||
{
|
||||
$webmentions = WebMention::all();
|
||||
foreach ($webmentions as $webmention) {
|
||||
$this->info('Initiation re-download of ' . $webmention->source);
|
||||
$this->info('Initiation re-download of '.$webmention->source);
|
||||
dispatch(new DownloadWebMention($webmention->source));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ namespace App\Http\Controllers\Admin;
|
|||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Contact;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\BadResponseException;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Arr;
|
||||
|
|
@ -75,7 +76,7 @@ class ContactsController extends Controller
|
|||
|
||||
if (request()->hasFile('avatar') && (request()->input('homepage') != '')) {
|
||||
$dir = parse_url(request()->input('homepage'), PHP_URL_HOST);
|
||||
$destination = public_path() . '/assets/profile-images/' . $dir;
|
||||
$destination = public_path().'/assets/profile-images/'.$dir;
|
||||
$filesystem = new Filesystem;
|
||||
if ($filesystem->isDirectory($destination) === false) {
|
||||
$filesystem->makeDirectory($destination);
|
||||
|
|
@ -103,7 +104,7 @@ class ContactsController extends Controller
|
|||
* This method attempts to find the microformat marked-up profile image
|
||||
* from a given homepage and save it accordingly
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse|\Illuminate\View\View
|
||||
* @return RedirectResponse|View
|
||||
*/
|
||||
public function getAvatar(int $contactId)
|
||||
{
|
||||
|
|
@ -115,8 +116,8 @@ class ContactsController extends Controller
|
|||
$client = resolve(Client::class);
|
||||
try {
|
||||
$response = $client->get($contact->homepage);
|
||||
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
|
||||
return redirect('/admin/contacts/' . $contactId . '/edit')
|
||||
} catch (BadResponseException $e) {
|
||||
return redirect('/admin/contacts/'.$contactId.'/edit')
|
||||
->with('error', 'Bad resposne from contact’s homepage');
|
||||
}
|
||||
$mf2 = \Mf2\parse((string) $response->getBody(), $contact->homepage);
|
||||
|
|
@ -129,18 +130,18 @@ class ContactsController extends Controller
|
|||
if ($avatarURL !== null) {
|
||||
try {
|
||||
$avatar = $client->get($avatarURL);
|
||||
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
|
||||
return redirect('/admin/contacts/' . $contactId . '/edit')
|
||||
} catch (BadResponseException $e) {
|
||||
return redirect('/admin/contacts/'.$contactId.'/edit')
|
||||
->with('error', 'Unable to download avatar');
|
||||
}
|
||||
}
|
||||
if ($avatar !== null) {
|
||||
$directory = public_path() . '/assets/profile-images/' . parse_url($contact->homepage, PHP_URL_HOST);
|
||||
$directory = public_path().'/assets/profile-images/'.parse_url($contact->homepage, PHP_URL_HOST);
|
||||
$filesystem = new Filesystem;
|
||||
if ($filesystem->isDirectory($directory) === false) {
|
||||
$filesystem->makeDirectory($directory);
|
||||
}
|
||||
$filesystem->put($directory . '/image', $avatar->getBody());
|
||||
$filesystem->put($directory.'/image', $avatar->getBody());
|
||||
|
||||
return view('admin.contacts.getavatarsuccess', [
|
||||
'homepage' => parse_url($contact->homepage, PHP_URL_HOST),
|
||||
|
|
@ -148,6 +149,6 @@ class ContactsController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
return redirect('/admin/contacts/' . $contactId . '/edit');
|
||||
return redirect('/admin/contacts/'.$contactId.'/edit');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ class PasskeysController extends Controller
|
|||
// Unset session data to mitigate replay attacks
|
||||
$request->session()->forget('create_options');
|
||||
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;
|
||||
|
|
@ -145,7 +145,7 @@ class PasskeysController extends Controller
|
|||
);
|
||||
|
||||
if (! $publicKeyCredential->response instanceof AuthenticatorAttestationResponse) {
|
||||
throw new WebAuthnException('Invalid response type');
|
||||
throw new WebauthnException('Invalid response type');
|
||||
}
|
||||
|
||||
$algorithmManager = new Manager;
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ class PlacesController extends Controller
|
|||
foreach ($place1->notes as $note) {
|
||||
$note->place()->dissociate();
|
||||
$note->place()->associate($place2->id);
|
||||
$note->save();
|
||||
}
|
||||
$place1->delete();
|
||||
}
|
||||
|
|
@ -127,6 +128,7 @@ class PlacesController extends Controller
|
|||
foreach ($place2->notes as $note) {
|
||||
$note->place()->dissociate();
|
||||
$note->place()->associate($place1->id);
|
||||
$note->save();
|
||||
}
|
||||
$place2->delete();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@ class ArticlesController extends Controller
|
|||
|
||||
if ($article->updated_at->year != $year || $article->updated_at->month != $month) {
|
||||
return redirect('/blog/'
|
||||
. $article->updated_at->year
|
||||
. '/' . $article->updated_at->format('m')
|
||||
. '/' . $slug);
|
||||
.$article->updated_at->year
|
||||
.'/'.$article->updated_at->format('m')
|
||||
.'/'.$slug);
|
||||
}
|
||||
|
||||
return view('articles.show', compact('article'));
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ class ContactsController extends Controller
|
|||
$contacts = Contact::all();
|
||||
foreach ($contacts as $contact) {
|
||||
$contact->homepageHost = parse_url($contact->homepage, PHP_URL_HOST);
|
||||
$file = public_path() . '/assets/profile-images/' . $contact->homepageHost . '/image';
|
||||
$file = public_path().'/assets/profile-images/'.$contact->homepageHost.'/image';
|
||||
$contact->image = ($filesystem->exists($file)) ?
|
||||
'/assets/profile-images/' . $contact->homepageHost . '/image'
|
||||
'/assets/profile-images/'.$contact->homepageHost.'/image'
|
||||
:
|
||||
'/assets/profile-images/default-image';
|
||||
}
|
||||
|
|
@ -35,11 +35,11 @@ class ContactsController extends Controller
|
|||
public function show(Contact $contact): View
|
||||
{
|
||||
$contact->homepageHost = parse_url($contact->homepage, PHP_URL_HOST);
|
||||
$file = public_path() . '/assets/profile-images/' . $contact->homepageHost . '/image';
|
||||
$file = public_path().'/assets/profile-images/'.$contact->homepageHost.'/image';
|
||||
|
||||
$filesystem = new Filesystem;
|
||||
$image = ($filesystem->exists($file)) ?
|
||||
'/assets/profile-images/' . $contact->homepageHost . '/image'
|
||||
'/assets/profile-images/'.$contact->homepageHost.'/image'
|
||||
:
|
||||
'/assets/profile-images/default-image';
|
||||
|
||||
|
|
|
|||
|
|
@ -71,9 +71,9 @@ class FeedsController extends Controller
|
|||
$articles = Article::where('published', '1')->latest('updated_at')->take(20)->get();
|
||||
$data = [
|
||||
'version' => 'https://jsonfeed.org/version/1.1',
|
||||
'title' => 'The JSON Feed for ' . config('user.display_name') . '’s blog',
|
||||
'home_page_url' => config('app.url') . '/blog',
|
||||
'feed_url' => config('app.url') . '/blog/feed.json',
|
||||
'title' => 'The JSON Feed for '.config('user.display_name').'’s blog',
|
||||
'home_page_url' => config('app.url').'/blog',
|
||||
'feed_url' => config('app.url').'/blog/feed.json',
|
||||
'authors' => [
|
||||
[
|
||||
'name' => config('user.display_name'),
|
||||
|
|
@ -85,9 +85,9 @@ class FeedsController extends Controller
|
|||
|
||||
foreach ($articles as $key => $article) {
|
||||
$data['items'][$key] = [
|
||||
'id' => config('app.url') . $article->link,
|
||||
'id' => config('app.url').$article->link,
|
||||
'title' => $article->title,
|
||||
'url' => config('app.url') . $article->link,
|
||||
'url' => config('app.url').$article->link,
|
||||
'content_html' => $article->main,
|
||||
'date_published' => $article->created_at->tz('UTC')->toRfc3339String(),
|
||||
'date_modified' => $article->updated_at->tz('UTC')->toRfc3339String(),
|
||||
|
|
@ -105,9 +105,9 @@ class FeedsController extends Controller
|
|||
$notes = Note::latest()->with('media', 'place', 'tags')->take(20)->get();
|
||||
$data = [
|
||||
'version' => 'https://jsonfeed.org/version/1.1',
|
||||
'title' => 'The JSON Feed for ' . config('user.display_name') . '’s notes',
|
||||
'home_page_url' => config('app.url') . '/notes',
|
||||
'feed_url' => config('app.url') . '/notes/feed.json',
|
||||
'title' => 'The JSON Feed for '.config('user.display_name').'’s notes',
|
||||
'home_page_url' => config('app.url').'/notes',
|
||||
'feed_url' => config('app.url').'/notes/feed.json',
|
||||
'authors' => [
|
||||
[
|
||||
'name' => config('user.display_name'),
|
||||
|
|
@ -144,8 +144,8 @@ class FeedsController extends Controller
|
|||
$items[] = [
|
||||
'type' => 'entry',
|
||||
'published' => $article->created_at,
|
||||
'uid' => config('app.url') . $article->link,
|
||||
'url' => config('app.url') . $article->link,
|
||||
'uid' => config('app.url').$article->link,
|
||||
'url' => config('app.url').$article->link,
|
||||
'content' => [
|
||||
'text' => $article->main,
|
||||
'html' => $article->html,
|
||||
|
|
@ -156,7 +156,7 @@ class FeedsController extends Controller
|
|||
|
||||
return response()->json([
|
||||
'type' => 'feed',
|
||||
'name' => 'Blog feed for ' . config('app.name'),
|
||||
'name' => 'Blog feed for '.config('app.name'),
|
||||
'url' => url('/blog'),
|
||||
'author' => [
|
||||
'type' => 'card',
|
||||
|
|
@ -192,7 +192,7 @@ class FeedsController extends Controller
|
|||
|
||||
return response()->json([
|
||||
'type' => 'feed',
|
||||
'name' => 'Notes feed for ' . config('app.name'),
|
||||
'name' => 'Notes feed for '.config('app.name'),
|
||||
'url' => url('/notes'),
|
||||
'author' => [
|
||||
'type' => 'card',
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ class MicropubMediaController extends Controller
|
|||
*/
|
||||
private function saveFileToLocal(UploadedFile $file): string
|
||||
{
|
||||
$filename = Uuid::uuid4()->toString() . '.' . $file->extension();
|
||||
$filename = Uuid::uuid4()->toString().'.'.$file->extension();
|
||||
Storage::disk('local')->putFileAs('', $file, $filename);
|
||||
|
||||
return $filename;
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class NotesController extends Controller
|
|||
*/
|
||||
public function redirect(int $decId): RedirectResponse
|
||||
{
|
||||
return redirect(config('app.url') . '/notes/' . (new Numbers)->numto60($decId));
|
||||
return redirect(config('app.url').'/notes/'.(new Numbers)->numto60($decId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@ class LinkHeadersMiddleware
|
|||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
$response = $next($request);
|
||||
$response->header('Link', '<' . route('indieauth.metadata') . '>; rel="indieauth-metadata"', false);
|
||||
$response->header('Link', '<' . route('indieauth.start') . '>; rel="authorization_endpoint"', false);
|
||||
$response->header('Link', '<' . route('indieauth.token') . '>; rel="token_endpoint"', false);
|
||||
$response->header('Link', '<' . route('micropub-endpoint') . '>; rel="micropub"', false);
|
||||
$response->header('Link', '<' . route('webmention-endpoint') . '>; rel="webmention"', false);
|
||||
$response->header('Link', '<'.route('indieauth.metadata').'>; rel="indieauth-metadata"', false);
|
||||
$response->header('Link', '<'.route('indieauth.start').'>; rel="authorization_endpoint"', false);
|
||||
$response->header('Link', '<'.route('indieauth.token').'>; rel="token_endpoint"', false);
|
||||
$response->header('Link', '<'.route('micropub-endpoint').'>; rel="micropub"', false);
|
||||
$response->header('Link', '<'.route('webmention-endpoint').'>; rel="webmention"', false);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class RedirectIfAuthenticated
|
|||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, string ...$guards): Response
|
||||
{
|
||||
|
|
|
|||
|
|
@ -39,9 +39,9 @@ class DownloadWebMention implements ShouldQueue
|
|||
// Laravel should catch and retry these automatically.
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$filesystem = new FileSystem;
|
||||
$filename = storage_path('HTML') . '/' . $this->createFilenameFromURL($this->source);
|
||||
$filename = storage_path('HTML').'/'.$this->createFilenameFromURL($this->source);
|
||||
// backup file first
|
||||
$filenameBackup = $filename . '.' . date('Y-m-d') . '.backup';
|
||||
$filenameBackup = $filename.'.'.date('Y-m-d').'.backup';
|
||||
if ($filesystem->exists($filename)) {
|
||||
$filesystem->copy($filename, $filenameBackup);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,8 @@ declare(strict_types=1);
|
|||
namespace App\Jobs;
|
||||
|
||||
use App\Models\Like;
|
||||
use Codebird\Codebird;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
|
|
@ -39,35 +37,6 @@ class ProcessLike implements ShouldQueue
|
|||
*/
|
||||
public function handle(Client $client, Authorship $authorship): int
|
||||
{
|
||||
if ($this->isTweet($this->like->url)) {
|
||||
$codebird = resolve(Codebird::class);
|
||||
|
||||
$tweet = $codebird->statuses_oembed(['url' => $this->like->url]);
|
||||
|
||||
$this->like->author_name = $tweet->author_name;
|
||||
$this->like->author_url = $tweet->author_url;
|
||||
$this->like->content = $tweet->html;
|
||||
$this->like->save();
|
||||
|
||||
// POSSE like
|
||||
try {
|
||||
$client->request(
|
||||
'POST',
|
||||
'https://brid.gy/publish/webmention',
|
||||
[
|
||||
'form_params' => [
|
||||
'source' => $this->like->url,
|
||||
'target' => 'https://brid.gy/publish/twitter',
|
||||
],
|
||||
]
|
||||
);
|
||||
} catch (RequestException) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$response = $client->request('GET', $this->like->url);
|
||||
$mf2 = \Mf2\parse((string) $response->getBody(), $this->like->url);
|
||||
if (Arr::has($mf2, 'items.0.properties.content')) {
|
||||
|
|
@ -91,15 +60,4 @@ class ProcessLike implements ShouldQueue
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given URL is that of a Tweet.
|
||||
*/
|
||||
private function isTweet(string $url): bool
|
||||
{
|
||||
$host = parse_url($url, PHP_URL_HOST);
|
||||
$parts = array_reverse(explode('.', $host));
|
||||
|
||||
return $parts[0] === 'com' && $parts[1] === 'twitter';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,10 +57,10 @@ class ProcessMedia implements ShouldQueue
|
|||
$basename = trim(implode('.', $filenameParts), '.');
|
||||
|
||||
$medium = $image->resize(width: 1000);
|
||||
Storage::disk('public')->put($basename . '-medium.' . $extension, (string) $medium->encode());
|
||||
Storage::disk('public')->put($basename.'-medium.'.$extension, (string) $medium->encode());
|
||||
|
||||
$small = $image->resize(width: 500);
|
||||
Storage::disk('public')->put($basename . '-small.' . $extension, (string) $small->encode());
|
||||
Storage::disk('public')->put($basename.'-small.'.$extension, (string) $small->encode());
|
||||
}
|
||||
|
||||
// Now we can delete the locally saved image
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ class ProcessWebMention implements ShouldQueue
|
|||
if (str_ends_with($url, '/')) {
|
||||
$filenameFromURL .= 'index.html';
|
||||
}
|
||||
$path = storage_path() . '/HTML/' . $filenameFromURL;
|
||||
$path = storage_path().'/HTML/'.$filenameFromURL;
|
||||
$parts = explode('/', $path);
|
||||
$name = array_pop($parts);
|
||||
$dir = implode('/', $parts);
|
||||
|
|
|
|||
|
|
@ -62,13 +62,13 @@ class SaveProfileImage implements ShouldQueue
|
|||
$image = $response->getBody();
|
||||
} catch (RequestException) {
|
||||
// we are opening and reading the default image so that
|
||||
$default = public_path() . '/assets/profile-images/default-image';
|
||||
$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';
|
||||
$path = public_path().'/assets/profile-images/'.parse_url($home, PHP_URL_HOST).'/image';
|
||||
$parts = explode('/', $path);
|
||||
$name = array_pop($parts);
|
||||
$dir = implode('/', $parts);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class SaveScreenshot implements ShouldQueue
|
|||
// First request that CloudConvert takes a screenshot of the URL
|
||||
$takeScreenshotJobResponse = $client->request('POST', 'https://api.cloudconvert.com/v2/capture-website', [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer ' . config('services.cloudconvert.token'),
|
||||
'Authorization' => 'Bearer '.config('services.cloudconvert.token'),
|
||||
],
|
||||
'json' => [
|
||||
'url' => $this->bookmark->url,
|
||||
|
|
@ -56,9 +56,9 @@ class SaveScreenshot implements ShouldQueue
|
|||
$taskId = json_decode($takeScreenshotJobResponse->getBody()->getContents(), false, 512, JSON_THROW_ON_ERROR)->data->id;
|
||||
|
||||
// Now wait till the status job is finished
|
||||
$screenshotJobStatusResponse = $retryClient->request('GET', 'https://api.cloudconvert.com/v2/tasks/' . $taskId, [
|
||||
$screenshotJobStatusResponse = $retryClient->request('GET', 'https://api.cloudconvert.com/v2/tasks/'.$taskId, [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer ' . config('services.cloudconvert.token'),
|
||||
'Authorization' => 'Bearer '.config('services.cloudconvert.token'),
|
||||
],
|
||||
'query' => [
|
||||
'include' => 'payload',
|
||||
|
|
@ -70,7 +70,7 @@ class SaveScreenshot implements ShouldQueue
|
|||
// Now we can create a new job to request thst the screenshot is exported to a temporary URL we can download the screenshot from
|
||||
$exportImageJob = $client->request('POST', 'https://api.cloudconvert.com/v2/export/url', [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer ' . config('services.cloudconvert.token'),
|
||||
'Authorization' => 'Bearer '.config('services.cloudconvert.token'),
|
||||
],
|
||||
'json' => [
|
||||
'input' => $finishedCaptureId,
|
||||
|
|
@ -81,9 +81,9 @@ class SaveScreenshot implements ShouldQueue
|
|||
$exportImageJobId = json_decode($exportImageJob->getBody()->getContents(), false, 512, JSON_THROW_ON_ERROR)->data->id;
|
||||
|
||||
// Again, wait till the status of this export job is finished
|
||||
$finalImageUrlResponse = $retryClient->request('GET', 'https://api.cloudconvert.com/v2/tasks/' . $exportImageJobId, [
|
||||
$finalImageUrlResponse = $retryClient->request('GET', 'https://api.cloudconvert.com/v2/tasks/'.$exportImageJobId, [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer ' . config('services.cloudconvert.token'),
|
||||
'Authorization' => 'Bearer '.config('services.cloudconvert.token'),
|
||||
],
|
||||
'query' => [
|
||||
'include' => 'payload',
|
||||
|
|
@ -95,7 +95,7 @@ class SaveScreenshot implements ShouldQueue
|
|||
|
||||
$finalImageUrlContent = $client->request('GET', $finalImageUrl);
|
||||
|
||||
Storage::disk('public')->put('/assets/img/bookmarks/' . $taskId . '.png', $finalImageUrlContent->getBody()->getContents());
|
||||
Storage::disk('public')->put('/assets/img/bookmarks/'.$taskId.'.png', $finalImageUrlContent->getBody()->getContents());
|
||||
|
||||
$this->bookmark->screenshot = $taskId;
|
||||
$this->bookmark->save();
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
|
|||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Str;
|
||||
use Mf2\Parser;
|
||||
|
||||
class SendWebMentions implements ShouldQueue
|
||||
{
|
||||
|
|
@ -83,7 +84,11 @@ class SendWebMentions implements ShouldQueue
|
|||
// failed to find a header so parse HTML
|
||||
$html = (string) $response->getBody();
|
||||
|
||||
$mf2 = new \Mf2\Parser($html, $url);
|
||||
if ($html === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$mf2 = new Parser($html, $url);
|
||||
$rels = $mf2->parseRelsAndAlternates();
|
||||
if (array_key_exists('webmention', $rels[0])) {
|
||||
$endpoint = $rels[0]['webmention'][0];
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class SyndicateNoteToBluesky implements ShouldQueue
|
|||
'https://brid.gy/micropub',
|
||||
[
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer ' . config('bridgy.bluesky_token'),
|
||||
'Authorization' => 'Bearer '.config('bridgy.bluesky_token'),
|
||||
],
|
||||
'json' => [
|
||||
'type' => ['h-entry'],
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class SyndicateNoteToMastodon implements ShouldQueue
|
|||
'https://brid.gy/micropub',
|
||||
[
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer ' . config('bridgy.mastodon_token'),
|
||||
'Authorization' => 'Bearer '.config('bridgy.mastodon_token'),
|
||||
],
|
||||
'json' => [
|
||||
'type' => ['h-entry'],
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ declare(strict_types=1);
|
|||
namespace App\Models;
|
||||
|
||||
use Cviebrock\EloquentSluggable\Sluggable;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Attributes\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
|
@ -18,23 +20,14 @@ use League\CommonMark\MarkdownConverter;
|
|||
use Spatie\CommonMarkHighlighter\FencedCodeRenderer;
|
||||
use Spatie\CommonMarkHighlighter\IndentedCodeRenderer;
|
||||
|
||||
#[Table('articles')]
|
||||
#[Fillable(['url', 'title', 'main', 'published'])]
|
||||
class Article extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Sluggable;
|
||||
use SoftDeletes;
|
||||
|
||||
/** @var string */
|
||||
protected $table = 'articles';
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $fillable = [
|
||||
'url',
|
||||
'title',
|
||||
'main',
|
||||
'published',
|
||||
];
|
||||
|
||||
/** @var array<string, string> */
|
||||
protected $casts = [
|
||||
'created_at' => 'datetime',
|
||||
|
|
@ -100,7 +93,7 @@ class Article extends Model
|
|||
protected function link(): Attribute
|
||||
{
|
||||
return Attribute::get(
|
||||
get: fn () => '/blog/' . $this->updated_at->year . '/' . $this->updated_at->format('m') . '/' . $this->titleurl,
|
||||
get: fn () => '/blog/'.$this->updated_at->year.'/'.$this->updated_at->format('m').'/'.$this->titleurl,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -112,15 +105,15 @@ class Article extends Model
|
|||
if ($year === null) {
|
||||
return $query;
|
||||
}
|
||||
$start = $year . '-01-01 00:00:00';
|
||||
$end = ($year + 1) . '-01-01 00:00:00';
|
||||
$start = $year.'-01-01 00:00:00';
|
||||
$end = ($year + 1).'-01-01 00:00:00';
|
||||
if (($month !== null) && ($month !== 12)) {
|
||||
$start = $year . '-' . $month . '-01 00:00:00';
|
||||
$end = $year . '-' . ($month + 1) . '-01 00:00:00';
|
||||
$start = $year.'-'.$month.'-01 00:00:00';
|
||||
$end = $year.'-'.($month + 1).'-01 00:00:00';
|
||||
}
|
||||
if ($month === 12) {
|
||||
$start = $year . '-12-01 00:00:00';
|
||||
$end = ($year + 1) . '-01-01 00:00:00';
|
||||
$start = $year.'-12-01 00:00:00';
|
||||
$end = ($year + 1).'-01-01 00:00:00';
|
||||
}
|
||||
|
||||
return $query->where([
|
||||
|
|
|
|||
|
|
@ -4,18 +4,17 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
#[Fillable(['url', 'name', 'content'])]
|
||||
class Bookmark extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $fillable = ['url', 'name', 'content'];
|
||||
|
||||
/** @var array<string, string> */
|
||||
protected $casts = [
|
||||
'syndicates' => 'array',
|
||||
|
|
@ -26,10 +25,10 @@ class Bookmark extends Model
|
|||
return $this->belongsToMany('App\Models\Tag');
|
||||
}
|
||||
|
||||
protected function local_uri(): Attribute
|
||||
protected function localUri(): Attribute
|
||||
{
|
||||
return Attribute::get(
|
||||
get: fn () => config('app.url') . '/bookmarks/' . $this->id,
|
||||
get: fn () => config('app.url').'/bookmarks/'.$this->id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,28 +4,26 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Attributes\Table;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
#[Table('contacts')]
|
||||
#[Fillable(['nick', 'name', 'homepage', 'twitter', 'facebook'])]
|
||||
class Contact extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/** @var string */
|
||||
protected $table = 'contacts';
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $fillable = ['nick', 'name', 'homepage', 'twitter', 'facebook'];
|
||||
|
||||
protected function photo(): Attribute
|
||||
{
|
||||
$photo = '/assets/profile-images/default-image';
|
||||
|
||||
if (array_key_exists('homepage', $this->attributes) && ! empty($this->attributes['homepage'])) {
|
||||
$host = parse_url($this->attributes['homepage'], PHP_URL_HOST);
|
||||
if (file_exists(public_path() . '/assets/profile-images/' . $host . '/image')) {
|
||||
$photo = '/assets/profile-images/' . $host . '/image';
|
||||
if (file_exists(public_path().'/assets/profile-images/'.$host.'/image')) {
|
||||
$photo = '/assets/profile-images/'.$host.'/image';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,20 +5,19 @@ declare(strict_types=1);
|
|||
namespace App\Models;
|
||||
|
||||
use App\Traits\FilterHtml;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
use Mf2;
|
||||
|
||||
#[Fillable(['url'])]
|
||||
class Like extends Model
|
||||
{
|
||||
use FilterHtml;
|
||||
use HasFactory;
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $fillable = ['url'];
|
||||
|
||||
protected function url(): Attribute
|
||||
{
|
||||
return Attribute::set(
|
||||
|
|
|
|||
|
|
@ -4,22 +4,20 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Attributes\Table;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
#[Table('media_endpoint')]
|
||||
#[Fillable(['token', 'path', 'type', 'image_widths'])]
|
||||
class Media extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/** @var string */
|
||||
protected $table = 'media_endpoint';
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $fillable = ['token', 'path', 'type', 'image_widths'];
|
||||
|
||||
public function notes(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Note::class)
|
||||
|
|
@ -35,7 +33,7 @@ class Media extends Model
|
|||
return $attributes['path'];
|
||||
}
|
||||
|
||||
return config('app.url') . '/storage/' . $attributes['path'];
|
||||
return config('app.url').'/storage/'.$attributes['path'];
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -80,7 +78,7 @@ class Media extends Model
|
|||
$basename = $this->getBasename($path);
|
||||
$extension = $this->getExtension($path);
|
||||
|
||||
return config('app.url') . '/storage/' . $basename . '-' . $size . '.' . $extension;
|
||||
return config('app.url').'/storage/'.$basename.'-'.$size.'.'.$extension;
|
||||
}
|
||||
|
||||
private function getBasename(string $path): string
|
||||
|
|
@ -91,7 +89,7 @@ class Media extends Model
|
|||
array_pop($filenameParts);
|
||||
|
||||
return ltrim(array_reduce($filenameParts, static function ($carry, $item) {
|
||||
return $carry . '.' . $item;
|
||||
return $carry.'.'.$item;
|
||||
}, ''), '.');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,20 +4,18 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Attributes\Table;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
#[Table('clients')]
|
||||
#[Fillable(['client_url', 'client_name'])]
|
||||
class MicropubClient extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/** @var string */
|
||||
protected $table = 'clients';
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $fillable = ['client_url', 'client_name'];
|
||||
|
||||
public function notes(): HasMany
|
||||
{
|
||||
return $this->hasMany('App\Models\Note', 'client_id', 'client_url');
|
||||
|
|
|
|||
|
|
@ -6,9 +6,12 @@ namespace App\Models;
|
|||
|
||||
use App\CommonMark\Generators\MentionGenerator;
|
||||
use App\CommonMark\Renderers\MentionRenderer;
|
||||
use Codebird\Codebird;
|
||||
use Exception;
|
||||
use App\Observers\NoteObserver;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Attributes\Hidden;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
use Illuminate\Database\Eloquent\Attributes\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
|
@ -31,6 +34,10 @@ use Normalizer;
|
|||
use Spatie\CommonMarkHighlighter\FencedCodeRenderer;
|
||||
use Spatie\CommonMarkHighlighter\IndentedCodeRenderer;
|
||||
|
||||
#[Table('notes')]
|
||||
#[Fillable(['note', 'in_reply_to', 'client_id'])]
|
||||
#[Hidden(['searchable'])]
|
||||
#[ObservedBy(NoteObserver::class)]
|
||||
class Note extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
|
@ -61,16 +68,6 @@ class Note extends Model
|
|||
/** @var string */
|
||||
protected $table = 'notes';
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $fillable = [
|
||||
'note',
|
||||
'in_reply_to',
|
||||
'client_id',
|
||||
];
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $hidden = ['searchable'];
|
||||
|
||||
public function tags(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Tag::class);
|
||||
|
|
@ -126,7 +123,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->uri.'">'.$this->place->name.'</a>';
|
||||
}
|
||||
|
||||
// if $value is still null, just return null
|
||||
|
|
@ -150,13 +147,13 @@ class Note extends Model
|
|||
|
||||
foreach ($this->media as $media) {
|
||||
if ($media->type === 'image') {
|
||||
$note .= PHP_EOL . '<img src="' . $media->url . '" alt="">';
|
||||
$note .= PHP_EOL.'<img src="'.$media->url.'" alt="">';
|
||||
}
|
||||
if ($media->type === 'audio') {
|
||||
$note .= PHP_EOL . '<audio src="' . $media->url . '">';
|
||||
$note .= PHP_EOL.'<audio src="'.$media->url.'">';
|
||||
}
|
||||
if ($media->type === 'video') {
|
||||
$note .= PHP_EOL . '<video src="' . $media->url . '">';
|
||||
$note .= PHP_EOL.'<video src="'.$media->url.'">';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -176,7 +173,7 @@ class Note extends Model
|
|||
|
||||
public function getUriAttribute(): string
|
||||
{
|
||||
return config('app.url') . '/notes/' . $this->nb60id;
|
||||
return config('app.url').'/notes/'.$this->nb60id;
|
||||
}
|
||||
|
||||
public function getIso8601Attribute(): string
|
||||
|
|
@ -241,43 +238,6 @@ class Note extends Model
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the OEmbed html for a tweet the note is a reply to.
|
||||
*/
|
||||
public function getTwitterAttribute(): ?object
|
||||
{
|
||||
if (
|
||||
$this->in_reply_to === null ||
|
||||
! $this->isTwitterLink($this->in_reply_to)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$tweetId = basename($this->in_reply_to);
|
||||
if (Cache::has($tweetId)) {
|
||||
return Cache::get($tweetId);
|
||||
}
|
||||
|
||||
try {
|
||||
$codebird = resolve(Codebird::class);
|
||||
$oEmbed = $codebird->statuses_oembed([
|
||||
'url' => $this->in_reply_to,
|
||||
'dnt' => true,
|
||||
'align' => 'center',
|
||||
'maxwidth' => 512,
|
||||
]);
|
||||
|
||||
if ($oEmbed->httpstatus >= 400) {
|
||||
throw new Exception;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
return null;
|
||||
}
|
||||
Cache::put($tweetId, $oEmbed, ($oEmbed->cache_age));
|
||||
|
||||
return $oEmbed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope a query to select a note via a NewBase60 id.
|
||||
*/
|
||||
|
|
@ -313,14 +273,14 @@ class Note extends Model
|
|||
self::USERNAMES_REGEX,
|
||||
function ($matches) {
|
||||
if (is_null($this->contacts[$matches[1]])) {
|
||||
return '<a href="https://twitter.com/' . $matches[1] . '">' . $matches[0] . '</a>';
|
||||
return '<a href="https://twitter.com/'.$matches[1].'">'.$matches[0].'</a>';
|
||||
}
|
||||
|
||||
$contact = $this->contacts[$matches[1]]; // easier to read the following code
|
||||
$host = parse_url($contact->homepage, PHP_URL_HOST);
|
||||
$contact->photo = '/assets/profile-images/default-image';
|
||||
if (file_exists(public_path() . '/assets/profile-images/' . $host . '/image')) {
|
||||
$contact->photo = '/assets/profile-images/' . $host . '/image';
|
||||
if (file_exists(public_path().'/assets/profile-images/'.$host.'/image')) {
|
||||
$contact->photo = '/assets/profile-images/'.$host.'/image';
|
||||
}
|
||||
|
||||
return trim(view('templates.mini-hcard', ['contact' => $contact])->render());
|
||||
|
|
@ -371,8 +331,8 @@ class Note extends Model
|
|||
'/#([^\s[:punct:]]+)/',
|
||||
function ($matches) {
|
||||
return '<a rel="tag" class="p-category" href="/notes/tagged/'
|
||||
. Tag::normalize($matches[1]) . '">#'
|
||||
. $matches[1] . '</a>';
|
||||
.Tag::normalize($matches[1]).'">#'
|
||||
.$matches[1].'</a>';
|
||||
},
|
||||
$note
|
||||
);
|
||||
|
|
@ -404,7 +364,7 @@ class Note extends Model
|
|||
|
||||
public function reverseGeoCode(float $latitude, float $longitude): string
|
||||
{
|
||||
$latLng = $latitude . ',' . $longitude;
|
||||
$latLng = $latitude.','.$longitude;
|
||||
|
||||
return Cache::get($latLng, function () use ($latLng, $latitude, $longitude) {
|
||||
$guzzle = resolve(Client::class);
|
||||
|
|
@ -422,46 +382,41 @@ class Note extends Model
|
|||
if (isset($json->address->suburb)) {
|
||||
$locality = $json->address->suburb;
|
||||
if (isset($json->address->city)) {
|
||||
$locality .= ', ' . $json->address->city;
|
||||
$locality .= ', '.$json->address->city;
|
||||
}
|
||||
$address = '<span class="p-locality">'
|
||||
. $locality
|
||||
. '</span>, <span class="p-country-name">'
|
||||
. $json->address->country
|
||||
. '</span>';
|
||||
.$locality
|
||||
.'</span>, <span class="p-country-name">'
|
||||
.$json->address->country
|
||||
.'</span>';
|
||||
Cache::forever($latLng, $address);
|
||||
|
||||
return $address;
|
||||
}
|
||||
if (isset($json->address->city)) {
|
||||
$address = '<span class="p-locality">'
|
||||
. $json->address->city
|
||||
. '</span>, <span class="p-country-name">'
|
||||
. $json->address->country
|
||||
. '</span>';
|
||||
.$json->address->city
|
||||
.'</span>, <span class="p-country-name">'
|
||||
.$json->address->country
|
||||
.'</span>';
|
||||
Cache::forever($latLng, $address);
|
||||
|
||||
return $address;
|
||||
}
|
||||
if (isset($json->address->county)) {
|
||||
$address = '<span class="p-region">'
|
||||
. $json->address->county
|
||||
. '</span>, <span class="p-country-name">'
|
||||
. $json->address->country
|
||||
. '</span>';
|
||||
.$json->address->county
|
||||
.'</span>, <span class="p-country-name">'
|
||||
.$json->address->country
|
||||
.'</span>';
|
||||
Cache::forever($latLng, $address);
|
||||
|
||||
return $address;
|
||||
}
|
||||
$address = '<span class="p-country-name">' . $json->address->country . '</span>';
|
||||
$address = '<span class="p-country-name">'.$json->address->country.'</span>';
|
||||
Cache::forever($latLng, $address);
|
||||
|
||||
return $address;
|
||||
});
|
||||
}
|
||||
|
||||
private function isTwitterLink(string $inReplyTo): bool
|
||||
{
|
||||
return str_starts_with($inReplyTo, 'https://twitter.com/');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,20 +4,16 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
#[Fillable(['passkey_id', 'passkey'])]
|
||||
class Passkey extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/** @inerhitDoc */
|
||||
protected $fillable = [
|
||||
'passkey_id',
|
||||
'passkey',
|
||||
];
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||
namespace App\Models;
|
||||
|
||||
use Cviebrock\EloquentSluggable\Sluggable;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
|
@ -12,6 +13,7 @@ use Illuminate\Database\Eloquent\Model;
|
|||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
#[Fillable(['name', 'slug'])]
|
||||
class Place extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
|
@ -22,9 +24,6 @@ class Place extends Model
|
|||
return 'slug';
|
||||
}
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $fillable = ['name', 'slug'];
|
||||
|
||||
/** @var array<string, string> */
|
||||
protected $casts = [
|
||||
'latitude' => 'float',
|
||||
|
|
@ -77,7 +76,7 @@ class Place extends Model
|
|||
protected function uri(): Attribute
|
||||
{
|
||||
return Attribute::get(
|
||||
get: static fn ($value, $attributes) => config('app.url') . '/places/' . $attributes['slug'],
|
||||
get: static fn ($value, $attributes) => config('app.url').'/places/'.$attributes['slug'],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,40 +4,20 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Attributes\Appends;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Attributes\Visible;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
#[Fillable(['uid', 'name', 'service_name', 'service_url', 'service_photo', 'user_name', 'user_url', 'user_photo'])]
|
||||
#[Visible(['uid', 'name', 'service', 'user'])]
|
||||
#[Appends(['service', 'user'])]
|
||||
class SyndicationTarget extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $fillable = [
|
||||
'uid',
|
||||
'name',
|
||||
'service_name',
|
||||
'service_url',
|
||||
'service_photo',
|
||||
'user_name',
|
||||
'user_url',
|
||||
'user_photo',
|
||||
];
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $visible = [
|
||||
'uid',
|
||||
'name',
|
||||
'service',
|
||||
'user',
|
||||
];
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $appends = [
|
||||
'service',
|
||||
'user',
|
||||
];
|
||||
|
||||
protected function service(): Attribute
|
||||
{
|
||||
return Attribute::get(
|
||||
|
|
|
|||
|
|
@ -4,19 +4,18 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
#[Guarded(['id'])]
|
||||
class Tag extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $guarded = ['id'];
|
||||
|
||||
public function notes(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Note::class);
|
||||
|
|
|
|||
|
|
@ -4,27 +4,34 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Database\Factories\UserFactory;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Attributes\Hidden;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
#[Fillable(['name', 'password'])]
|
||||
#[Hidden(['password', 'remember_token'])]
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasFactory;
|
||||
use Notifiable;
|
||||
/** @use HasFactory<UserFactory> */
|
||||
use HasFactory, Notifiable;
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $fillable = [
|
||||
'name', 'password',
|
||||
];
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $hidden = [
|
||||
'current_password',
|
||||
'password',
|
||||
'remember_token',
|
||||
];
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
];
|
||||
}
|
||||
|
||||
public function passkey(): HasMany
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,27 +5,23 @@ declare(strict_types=1);
|
|||
namespace App\Models;
|
||||
|
||||
use App\Traits\FilterHtml;
|
||||
use Codebird\Codebird;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Attributes\Guarded;
|
||||
use Illuminate\Database\Eloquent\Attributes\Table;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Jonnybarnes\WebmentionsParser\Authorship;
|
||||
|
||||
#[Table('webmentions')]
|
||||
#[Guarded(['id'])]
|
||||
class WebMention extends Model
|
||||
{
|
||||
use FilterHtml;
|
||||
use HasFactory;
|
||||
|
||||
/** @var string */
|
||||
protected $table = 'webmentions';
|
||||
|
||||
/** @var array<int, string> */
|
||||
protected $guarded = ['id'];
|
||||
|
||||
public function commentable(): MorphTo
|
||||
{
|
||||
return $this->morphTo();
|
||||
|
|
@ -127,22 +123,9 @@ class WebMention extends Model
|
|||
return str_replace('http://', 'https://', $url);
|
||||
}
|
||||
|
||||
if ($host === 'twitter.com') {
|
||||
if (Cache::has($url)) {
|
||||
return Cache::get($url);
|
||||
}
|
||||
$username = ltrim(parse_url($url, PHP_URL_PATH), '/');
|
||||
$codebird = resolve(Codebird::class);
|
||||
$info = $codebird->users_show(['screen_name' => $username]);
|
||||
$profile_image = $info->profile_image_url_https;
|
||||
Cache::put($url, $profile_image, 10080); // 1 week
|
||||
|
||||
return $profile_image;
|
||||
}
|
||||
|
||||
$filesystem = new Filesystem;
|
||||
if ($filesystem->exists(public_path() . '/assets/profile-images/' . $host . '/image')) {
|
||||
return '/assets/profile-images/' . $host . '/image';
|
||||
if ($filesystem->exists(public_path().'/assets/profile-images/'.$host.'/image')) {
|
||||
return '/assets/profile-images/'.$host.'/image';
|
||||
}
|
||||
|
||||
return $url;
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\Note;
|
||||
use App\Observers\NoteObserver;
|
||||
use Codebird\Codebird;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Middleware;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Intervention\Image\ImageManager;
|
||||
use Lcobucci\JWT\Configuration;
|
||||
use Lcobucci\JWT\Signer\Hmac\Sha256;
|
||||
use Lcobucci\JWT\Signer\Key\InMemory;
|
||||
|
|
@ -33,33 +33,11 @@ class AppServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
Note::observe(NoteObserver::class);
|
||||
|
||||
// configure Intervention/Image
|
||||
$this->app->bind('Intervention\Image\ImageManager', function () {
|
||||
return \Intervention\Image\ImageManager::withDriver(config('image.driver'));
|
||||
return ImageManager::withDriver(config('image.driver'));
|
||||
});
|
||||
|
||||
// Bind the Codebird client
|
||||
// Codebird gets mocked in tests
|
||||
// @codeCoverageIgnoreStart
|
||||
$this->app->bind('Codebird\Codebird', function () {
|
||||
Codebird::setConsumerKey(
|
||||
env('TWITTER_CONSUMER_KEY'),
|
||||
env('TWITTER_CONSUMER_SECRET')
|
||||
);
|
||||
|
||||
$cb = Codebird::getInstance();
|
||||
|
||||
$cb->setToken(
|
||||
env('TWITTER_ACCESS_TOKEN'),
|
||||
env('TWITTER_ACCESS_TOKEN_SECRET')
|
||||
);
|
||||
|
||||
return $cb;
|
||||
});
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
/**
|
||||
* Paginate a standard Laravel Collection.
|
||||
*
|
||||
|
|
@ -106,7 +84,7 @@ class AppServiceProvider extends ServiceProvider
|
|||
|
||||
// Configure Guzzle
|
||||
$this->app->bind('RetryGuzzle', function () {
|
||||
$handlerStack = \GuzzleHttp\HandlerStack::create();
|
||||
$handlerStack = HandlerStack::create();
|
||||
$handlerStack->push(Middleware::retry(
|
||||
function ($retries, $request, $response, $exception) {
|
||||
// Limit the number of retries to 5
|
||||
|
|
@ -115,7 +93,7 @@ class AppServiceProvider extends ServiceProvider
|
|||
}
|
||||
|
||||
// Retry connection exceptions
|
||||
if ($exception instanceof \GuzzleHttp\Exception\ConnectException) {
|
||||
if ($exception instanceof ConnectException) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class BookmarkService
|
|||
{
|
||||
$client = resolve(Client::class);
|
||||
try {
|
||||
$response = $client->request('GET', 'https://web.archive.org/save/' . $url);
|
||||
$response = $client->request('GET', 'https://web.archive.org/save/'.$url);
|
||||
} catch (ClientException $e) {
|
||||
// throw an exception to be caught
|
||||
throw new InternetArchiveException;
|
||||
|
|
|
|||
|
|
@ -53,9 +53,9 @@ class UpdateHandler implements MicropubHandlerInterface
|
|||
if ($data->updateReplace !== null) {
|
||||
foreach ($data->updateReplace as $property => $value) {
|
||||
match ($property) {
|
||||
'content' => $note->note = is_array($value[0]) ? ($value[0]['html'] ?? $value[0]['value'] ?? null) : $value[0],
|
||||
'content' => $note->note = is_array($value[0]) ? ($value[0]['html'] ?? $value[0]['value'] ?? null) : $value[0],
|
||||
'syndication' => $this->applySyndication($note, $value),
|
||||
default => null,
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -97,8 +97,8 @@ class UpdateHandler implements MicropubHandlerInterface
|
|||
foreach ($delete as $property) {
|
||||
match ($property) {
|
||||
'syndication' => $this->clearSyndication($note),
|
||||
'photo' => $note->media()->delete(),
|
||||
default => null,
|
||||
'photo' => $note->media()->delete(),
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ class NoteService
|
|||
$matches
|
||||
);
|
||||
|
||||
return $matches[0][0] . ', ' . $matches[0][1];
|
||||
return $matches[0][0].', '.$matches[0][1];
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
|||
Loading…
Reference in a new issue