commit
7d1738964a
56 changed files with 3884 additions and 4694 deletions
8
.github/workflows/deploy.yml
vendored
8
.github/workflows/deploy.yml
vendored
|
@ -21,6 +21,12 @@ jobs:
|
|||
- name: 🌎 Set Environment Variables Part 2
|
||||
run: |
|
||||
echo "newReleaseDir=${{ env.releasesDir }}/${{ env.newReleaseName }}" >> $GITHUB_ENV
|
||||
- name: 🔀 Get Branch
|
||||
id: branch
|
||||
run: |
|
||||
echo "branch=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV
|
||||
- name: 🔍 Check Branch
|
||||
run: echo "${{ env.branch }}"
|
||||
- name: 🔄 Clone Repository
|
||||
uses: appleboy/ssh-action@master
|
||||
with:
|
||||
|
@ -39,7 +45,7 @@ jobs:
|
|||
mkdir ${{ env.newReleaseDir }}
|
||||
|
||||
# Clone app
|
||||
git clone --depth 1 --branch main https://github.com/${{ env.repository }} ${{ env.newReleaseName }}
|
||||
git clone --depth 1 --branch ${{ env.branch }} https://github.com/${{ env.repository }} ${{ env.newReleaseName }}
|
||||
|
||||
# Mark release
|
||||
cd ${{ env.newReleaseDir }}
|
||||
|
|
|
@ -6,6 +6,9 @@ use App\Models\Place;
|
|||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class MigratePlaceDataFromPostgis extends Command
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -22,11 +22,11 @@ class Kernel extends ConsoleKernel
|
|||
*
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||
* @return void
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
$schedule->command('horizon:snapshot')->everyFiveMinutes();
|
||||
$schedule->command('telescope:prune --hours=48')->daily();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -138,8 +138,8 @@ class ContactsController extends Controller
|
|||
}
|
||||
$mf2 = \Mf2\parse((string) $response->getBody(), $contact->homepage);
|
||||
foreach ($mf2['items'] as $microformat) {
|
||||
if (Arr::get($microformat, 'type.0') == 'h-card') {
|
||||
$avatarURL = Arr::get($microformat, 'properties.photo.0');
|
||||
if (Arr::get($microformat, 'type.0') === 'h-card') {
|
||||
$avatarURL = Arr::get($microformat, 'properties.photo.0.value');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Note;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class SearchController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display search results.
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function search(): View
|
||||
{
|
||||
$notes = Note::search(request()->input('terms'))->paginate(10);
|
||||
|
||||
return view('search', compact('notes'));
|
||||
}
|
||||
}
|
|
@ -4,6 +4,9 @@ namespace App\Http\Middleware;
|
|||
|
||||
use Illuminate\Auth\Middleware\Authenticate as Middleware;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class Authenticate extends Middleware
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,9 @@ use Closure;
|
|||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class RedirectIfAuthenticated
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -4,6 +4,9 @@ namespace App\Http\Middleware;
|
|||
|
||||
use Illuminate\Http\Middleware\TrustHosts as Middleware;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class TrustHosts extends Middleware
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Fideloper\Proxy\TrustProxies as Middleware;
|
||||
use Illuminate\Http\Middleware\TrustProxies as Middleware;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TrustProxies extends Middleware
|
||||
|
@ -19,5 +19,10 @@ class TrustProxies extends Middleware
|
|||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $headers = Request::HEADER_X_FORWARDED_ALL;
|
||||
protected $headers =
|
||||
Request::HEADER_X_FORWARDED_FOR |
|
||||
Request::HEADER_X_FORWARDED_HOST |
|
||||
Request::HEADER_X_FORWARDED_PORT |
|
||||
Request::HEADER_X_FORWARDED_PROTO |
|
||||
Request::HEADER_X_FORWARDED_AWS_ELB;
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ class ProcessLike implements ShouldQueue
|
|||
|
||||
//POSSE like
|
||||
try {
|
||||
$response = $client->request(
|
||||
$client->request(
|
||||
'POST',
|
||||
'https://brid.gy/publish/webmention',
|
||||
[
|
||||
|
@ -70,8 +70,8 @@ class ProcessLike implements ShouldQueue
|
|||
],
|
||||
]
|
||||
);
|
||||
} catch (RequestException $exception) {
|
||||
//no biggie
|
||||
} catch (RequestException) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -5,58 +5,19 @@ declare(strict_types=1);
|
|||
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;
|
||||
use League\CommonMark\Block\Element\FencedCode;
|
||||
use League\CommonMark\Block\Element\IndentedCode;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
use League\CommonMark\Environment;
|
||||
use League\CommonMark\Environment\Environment;
|
||||
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
|
||||
use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
|
||||
use League\CommonMark\Extension\CommonMark\Node\Block\IndentedCode;
|
||||
use League\CommonMark\MarkdownConverter;
|
||||
use Spatie\CommonMarkHighlighter\FencedCodeRenderer;
|
||||
use Spatie\CommonMarkHighlighter\IndentedCodeRenderer;
|
||||
|
||||
/**
|
||||
* App\Models\Article.
|
||||
*
|
||||
* @property int $id
|
||||
* @property string $titleurl
|
||||
* @property string|null $url
|
||||
* @property string $title
|
||||
* @property string $main
|
||||
* @property int $published
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
* @property Carbon|null $deleted_at
|
||||
* @property-read string $html
|
||||
* @property-read string $human_time
|
||||
* @property-read string $link
|
||||
* @property-read string $pubdate
|
||||
* @property-read string $tooltip_time
|
||||
* @property-read string $w3c_time
|
||||
* @method static Builder|Article date($year = null, $month = null)
|
||||
* @method static Builder|Article findSimilarSlugs($attribute, $config, $slug)
|
||||
* @method static bool|null forceDelete()
|
||||
* @method static Builder|Article newModelQuery()
|
||||
* @method static Builder|Article newQuery()
|
||||
* @method static \Illuminate\Database\Query\Builder|Article onlyTrashed()
|
||||
* @method static Builder|Article query()
|
||||
* @method static bool|null restore()
|
||||
* @method static Builder|Article whereCreatedAt($value)
|
||||
* @method static Builder|Article whereDeletedAt($value)
|
||||
* @method static Builder|Article whereId($value)
|
||||
* @method static Builder|Article whereMain($value)
|
||||
* @method static Builder|Article wherePublished($value)
|
||||
* @method static Builder|Article whereTitle($value)
|
||||
* @method static Builder|Article whereTitleurl($value)
|
||||
* @method static Builder|Article whereUpdatedAt($value)
|
||||
* @method static Builder|Article whereUrl($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|Article withTrashed()
|
||||
* @method static \Illuminate\Database\Query\Builder|Article withoutTrashed()
|
||||
* @mixin Eloquent
|
||||
*/
|
||||
class Article extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
@ -105,12 +66,13 @@ class Article extends Model
|
|||
*/
|
||||
public function getHtmlAttribute(): string
|
||||
{
|
||||
$environment = Environment::createCommonMarkEnvironment();
|
||||
$environment->addBlockRenderer(FencedCode::class, new FencedCodeRenderer());
|
||||
$environment->addBlockRenderer(IndentedCode::class, new IndentedCodeRenderer());
|
||||
$commonMarkConverter = new CommonMarkConverter([], $environment);
|
||||
$environment = new Environment();
|
||||
$environment->addExtension(new CommonMarkCoreExtension());
|
||||
$environment->addRenderer(FencedCode::class, new FencedCodeRenderer());
|
||||
$environment->addRenderer(IndentedCode::class, new IndentedCodeRenderer());
|
||||
$markdownConverter = new MarkdownConverter($environment);
|
||||
|
||||
return $commonMarkConverter->convertToHtml($this->main);
|
||||
return $markdownConverter->convert($this->main)->getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
|
|
@ -4,36 +4,11 @@ declare(strict_types=1);
|
|||
|
||||
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;
|
||||
|
||||
/**
|
||||
* App\Models\Contact.
|
||||
*
|
||||
* @property int $id
|
||||
* @property string $nick
|
||||
* @property string $name
|
||||
* @property string|null $homepage
|
||||
* @property string|null $twitter
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
* @property string|null $facebook
|
||||
* @method static Builder|Contact newModelQuery()
|
||||
* @method static Builder|Contact newQuery()
|
||||
* @method static Builder|Contact query()
|
||||
* @method static Builder|Contact whereCreatedAt($value)
|
||||
* @method static Builder|Contact whereFacebook($value)
|
||||
* @method static Builder|Contact whereHomepage($value)
|
||||
* @method static Builder|Contact whereId($value)
|
||||
* @method static Builder|Contact whereName($value)
|
||||
* @method static Builder|Contact whereNick($value)
|
||||
* @method static Builder|Contact whereTwitter($value)
|
||||
* @method static Builder|Contact whereUpdatedAt($value)
|
||||
* @mixin Eloquent
|
||||
*/
|
||||
class Contact extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||
namespace App\Models;
|
||||
|
||||
use App\Traits\FilterHtml;
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
@ -13,28 +12,6 @@ use Illuminate\Support\Arr;
|
|||
use Illuminate\Support\Carbon;
|
||||
use Mf2;
|
||||
|
||||
/**
|
||||
* App\Models\Like.
|
||||
*
|
||||
* @property int $id
|
||||
* @property string $url
|
||||
* @property string|null $author_name
|
||||
* @property string|null $author_url
|
||||
* @property string|null $content
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
* @method static Builder|Like newModelQuery()
|
||||
* @method static Builder|Like newQuery()
|
||||
* @method static Builder|Like query()
|
||||
* @method static Builder|Like whereAuthorName($value)
|
||||
* @method static Builder|Like whereAuthorUrl($value)
|
||||
* @method static Builder|Like whereContent($value)
|
||||
* @method static Builder|Like whereCreatedAt($value)
|
||||
* @method static Builder|Like whereId($value)
|
||||
* @method static Builder|Like whereUpdatedAt($value)
|
||||
* @method static Builder|Like whereUrl($value)
|
||||
* @mixin Eloquent
|
||||
*/
|
||||
class Like extends Model
|
||||
{
|
||||
use FilterHtml;
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
@ -12,34 +11,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* App\Models\Media.
|
||||
*
|
||||
* @property int $id
|
||||
* @property string|null $token
|
||||
* @property string $path
|
||||
* @property string $type
|
||||
* @property int|null $note_id
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
* @property string|null $image_widths
|
||||
* @property-read string $mediumurl
|
||||
* @property-read string $smallurl
|
||||
* @property-read string $url
|
||||
* @property-read Note|null $note
|
||||
* @method static Builder|Media newModelQuery()
|
||||
* @method static Builder|Media newQuery()
|
||||
* @method static Builder|Media query()
|
||||
* @method static Builder|Media whereCreatedAt($value)
|
||||
* @method static Builder|Media whereId($value)
|
||||
* @method static Builder|Media whereImageWidths($value)
|
||||
* @method static Builder|Media whereNoteId($value)
|
||||
* @method static Builder|Media wherePath($value)
|
||||
* @method static Builder|Media whereToken($value)
|
||||
* @method static Builder|Media whereType($value)
|
||||
* @method static Builder|Media whereUpdatedAt($value)
|
||||
* @mixin Eloquent
|
||||
*/
|
||||
class Media extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
@ -12,26 +11,6 @@ use Illuminate\Database\Eloquent\Model;
|
|||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
/**
|
||||
* App\Models\MicropubClient.
|
||||
*
|
||||
* @property int $id
|
||||
* @property string $client_url
|
||||
* @property string $client_name
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
* @property-read Collection|\App\Models\Note[] $notes
|
||||
* @property-read int|null $notes_count
|
||||
* @method static Builder|MicropubClient newModelQuery()
|
||||
* @method static Builder|MicropubClient newQuery()
|
||||
* @method static Builder|MicropubClient query()
|
||||
* @method static Builder|MicropubClient whereClientName($value)
|
||||
* @method static Builder|MicropubClient whereClientUrl($value)
|
||||
* @method static Builder|MicropubClient whereCreatedAt($value)
|
||||
* @method static Builder|MicropubClient whereId($value)
|
||||
* @method static Builder|MicropubClient whereUpdatedAt($value)
|
||||
* @mixin Eloquent
|
||||
*/
|
||||
class MicropubClient extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
|
|
@ -10,92 +10,22 @@ use Codebird\Codebird;
|
|||
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\Database\Eloquent\{Builder, Factories\HasFactory, Model, SoftDeletes};
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use Jonnybarnes\IndieWeb\Numbers;
|
||||
use Laravel\Scout\Searchable;
|
||||
use League\CommonMark\Block\Element\{FencedCode, IndentedCode};
|
||||
use League\CommonMark\Environment\Environment;
|
||||
use League\CommonMark\Extension\Autolink\AutolinkExtension;
|
||||
use League\CommonMark\{CommonMarkConverter, Environment};
|
||||
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
|
||||
use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
|
||||
use League\CommonMark\Extension\CommonMark\Node\Block\IndentedCode;
|
||||
use League\CommonMark\MarkdownConverter;
|
||||
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.
|
||||
*
|
||||
* @property int $id
|
||||
* @property string|null $note
|
||||
* @property string|null $in_reply_to
|
||||
* @property string $shorturl
|
||||
* @property string|null $location
|
||||
* @property int|null $photo
|
||||
* @property string|null $tweet_id
|
||||
* @property string|null $client_id
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
* @property Carbon|null $deleted_at
|
||||
* @property int|null $place_id
|
||||
* @property string|null $facebook_url
|
||||
* @property string|null $searchable
|
||||
* @property string|null $swarm_url
|
||||
* @property string|null $instagram_url
|
||||
* @property-read MicropubClient|null $client
|
||||
* @property-read string|null $address
|
||||
* @property-read string $content
|
||||
* @property-read string $humandiff
|
||||
* @property-read string $iso8601
|
||||
* @property-read float|null $latitude
|
||||
* @property-read float|null $longitude
|
||||
* @property-read string $longurl
|
||||
* @property-read string $nb60id
|
||||
* @property-read string $pubdate
|
||||
* @property-read object|null $twitter
|
||||
* @property-read string $twitter_content
|
||||
* @property-read Collection|Media[] $media
|
||||
* @property-read int|null $media_count
|
||||
* @property-read Place|null $place
|
||||
* @property-read Collection|Tag[] $tags
|
||||
* @property-read int|null $tags_count
|
||||
* @property-read Collection|WebMention[] $webmentions
|
||||
* @property-read int|null $webmentions_count
|
||||
* @method static bool|null forceDelete()
|
||||
* @method static Builder|Note nb60($nb60id)
|
||||
* @method static Builder|Note newModelQuery()
|
||||
* @method static Builder|Note newQuery()
|
||||
* @method static \Illuminate\Database\Query\Builder|Note onlyTrashed()
|
||||
* @method static Builder|Note query()
|
||||
* @method static bool|null restore()
|
||||
* @method static Builder|Note whereClientId($value)
|
||||
* @method static Builder|Note whereCreatedAt($value)
|
||||
* @method static Builder|Note whereDeletedAt($value)
|
||||
* @method static Builder|Note whereFacebookUrl($value)
|
||||
* @method static Builder|Note whereId($value)
|
||||
* @method static Builder|Note whereInReplyTo($value)
|
||||
* @method static Builder|Note whereInstagramUrl($value)
|
||||
* @method static Builder|Note whereLocation($value)
|
||||
* @method static Builder|Note whereNote($value)
|
||||
* @method static Builder|Note wherePhoto($value)
|
||||
* @method static Builder|Note wherePlaceId($value)
|
||||
* @method static Builder|Note whereSearchable($value)
|
||||
* @method static Builder|Note whereShorturl($value)
|
||||
* @method static Builder|Note whereSwarmUrl($value)
|
||||
* @method static Builder|Note whereTweetId($value)
|
||||
* @method static Builder|Note whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|Note withTrashed()
|
||||
* @method static \Illuminate\Database\Query\Builder|Note withoutTrashed()
|
||||
* @mixin Eloquent
|
||||
*/
|
||||
class Note extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use Searchable;
|
||||
use SoftDeletes;
|
||||
|
||||
/**
|
||||
|
@ -597,13 +527,14 @@ class Note extends Model
|
|||
*/
|
||||
private function convertMarkdown(string $note): string
|
||||
{
|
||||
$environment = Environment::createCommonMarkEnvironment();
|
||||
$environment = new Environment();
|
||||
$environment->addExtension(new CommonMarkCoreExtension());
|
||||
$environment->addExtension(new AutolinkExtension());
|
||||
$environment->addBlockRenderer(FencedCode::class, new FencedCodeRenderer());
|
||||
$environment->addBlockRenderer(IndentedCode::class, new IndentedCodeRenderer());
|
||||
$converter = new CommonMarkConverter([], $environment);
|
||||
$environment->addRenderer(FencedCode::class, new FencedCodeRenderer());
|
||||
$environment->addRenderer(IndentedCode::class, new IndentedCodeRenderer());
|
||||
$markdownConverter = new MarkdownConverter($environment);
|
||||
|
||||
return $converter->convertToHtml($note);
|
||||
return $markdownConverter->convert($note)->getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,50 +5,11 @@ declare(strict_types=1);
|
|||
namespace App\Models;
|
||||
|
||||
use Cviebrock\EloquentSluggable\Sluggable;
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\{Builder, Collection, Factories\HasFactory, Model};
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* App\Models\Place.
|
||||
*
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property string $slug
|
||||
* @property string|null $description
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
* @property string|null $icon
|
||||
* @property string|null $foursquare
|
||||
* @property mixed|null $external_urls
|
||||
* @property float|null $latitude
|
||||
* @property float|null $longitude
|
||||
* @property-read string $longurl
|
||||
* @property-read string $shorturl
|
||||
* @property-read string $uri
|
||||
* @property-read Collection|\App\Models\Note[] $notes
|
||||
* @property-read int|null $notes_count
|
||||
* @method static Builder|Place findSimilarSlugs($attribute, $config, $slug)
|
||||
* @method static Builder|Place near($location, $distance = 1000)
|
||||
* @method static Builder|Place newModelQuery()
|
||||
* @method static Builder|Place newQuery()
|
||||
* @method static Builder|Place query()
|
||||
* @method static Builder|Place whereCreatedAt($value)
|
||||
* @method static Builder|Place whereDescription($value)
|
||||
* @method static Builder|Place whereExternalURL($url)
|
||||
* @method static Builder|Place whereExternalUrls($value)
|
||||
* @method static Builder|Place whereFoursquare($value)
|
||||
* @method static Builder|Place whereIcon($value)
|
||||
* @method static Builder|Place whereId($value)
|
||||
* @method static Builder|Place whereLatitude($value)
|
||||
* @method static Builder|Place whereLongitude($value)
|
||||
* @method static Builder|Place whereName($value)
|
||||
* @method static Builder|Place whereSlug($value)
|
||||
* @method static Builder|Place whereUpdatedAt($value)
|
||||
* @mixin Eloquent
|
||||
*/
|
||||
class Place extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
@ -13,26 +12,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
|||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* App\Models\Tag.
|
||||
*
|
||||
* @property int $id
|
||||
* @property string $tag
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
* @property-read Collection|Bookmark[] $bookmarks
|
||||
* @property-read int|null $bookmarks_count
|
||||
* @property-read Collection|Note[] $notes
|
||||
* @property-read int|null $notes_count
|
||||
* @method static Builder|Tag newModelQuery()
|
||||
* @method static Builder|Tag newQuery()
|
||||
* @method static Builder|Tag query()
|
||||
* @method static Builder|Tag whereCreatedAt($value)
|
||||
* @method static Builder|Tag whereId($value)
|
||||
* @method static Builder|Tag whereTag($value)
|
||||
* @method static Builder|Tag whereUpdatedAt($value)
|
||||
* @mixin Eloquent
|
||||
*/
|
||||
class Tag extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
|
|
@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
|
@ -13,28 +12,6 @@ use Illuminate\Notifications\DatabaseNotificationCollection;
|
|||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
/**
|
||||
* App\Models\User.
|
||||
*
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property string $password
|
||||
* @property string|null $remember_token
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
* @property-read DatabaseNotificationCollection|DatabaseNotification[] $notifications
|
||||
* @property-read int|null $notifications_count
|
||||
* @method static Builder|User newModelQuery()
|
||||
* @method static Builder|User newQuery()
|
||||
* @method static Builder|User query()
|
||||
* @method static Builder|User whereCreatedAt($value)
|
||||
* @method static Builder|User whereId($value)
|
||||
* @method static Builder|User whereName($value)
|
||||
* @method static Builder|User wherePassword($value)
|
||||
* @method static Builder|User whereRememberToken($value)
|
||||
* @method static Builder|User whereUpdatedAt($value)
|
||||
* @mixin Eloquent
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasFactory;
|
||||
|
|
|
@ -6,7 +6,6 @@ namespace App\Models;
|
|||
|
||||
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;
|
||||
|
@ -17,42 +16,6 @@ use Illuminate\Support\Facades\Cache;
|
|||
use Jonnybarnes\WebmentionsParser\Authorship;
|
||||
use Jonnybarnes\WebmentionsParser\Exceptions\AuthorshipParserException;
|
||||
|
||||
/**
|
||||
* App\Models\WebMention.
|
||||
*
|
||||
* @property int $id
|
||||
* @property string $source
|
||||
* @property string $target
|
||||
* @property int|null $commentable_id
|
||||
* @property string|null $commentable_type
|
||||
* @property string|null $type
|
||||
* @property string|null $content
|
||||
* @property int $verified
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
* @property string|null $deleted_at
|
||||
* @property mixed|null $mf2
|
||||
* @property-read WebMention|null $commentable
|
||||
* @property-read array $author
|
||||
* @property-read string|null $published
|
||||
* @property-read string|null $reply
|
||||
* @method static Builder|WebMention newModelQuery()
|
||||
* @method static Builder|WebMention newQuery()
|
||||
* @method static Builder|WebMention query()
|
||||
* @method static Builder|WebMention whereCommentableId($value)
|
||||
* @method static Builder|WebMention whereCommentableType($value)
|
||||
* @method static Builder|WebMention whereContent($value)
|
||||
* @method static Builder|WebMention whereCreatedAt($value)
|
||||
* @method static Builder|WebMention whereDeletedAt($value)
|
||||
* @method static Builder|WebMention whereId($value)
|
||||
* @method static Builder|WebMention whereMf2($value)
|
||||
* @method static Builder|WebMention whereSource($value)
|
||||
* @method static Builder|WebMention whereTarget($value)
|
||||
* @method static Builder|WebMention whereType($value)
|
||||
* @method static Builder|WebMention whereUpdatedAt($value)
|
||||
* @method static Builder|WebMention whereVerified($value)
|
||||
* @mixin Eloquent
|
||||
*/
|
||||
class WebMention extends Model
|
||||
{
|
||||
use FilterHtml;
|
||||
|
|
|
@ -38,6 +38,8 @@ class AppServiceProvider extends ServiceProvider
|
|||
});
|
||||
|
||||
// Bind the Codebird client
|
||||
// Codebird gets mocked in tests
|
||||
// @codeCoverageIgnoreStart
|
||||
$this->app->bind('Codebird\Codebird', function () {
|
||||
Codebird::setConsumerKey(
|
||||
env('TWITTER_CONSUMER_KEY'),
|
||||
|
@ -53,6 +55,7 @@ class AppServiceProvider extends ServiceProvider
|
|||
|
||||
return $cb;
|
||||
});
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
/**
|
||||
* Paginate a standard Laravel Collection.
|
||||
|
|
|
@ -34,9 +34,7 @@ class HorizonServiceProvider extends HorizonApplicationServiceProvider
|
|||
protected function gate()
|
||||
{
|
||||
Gate::define('viewHorizon', function ($user) {
|
||||
return in_array($user->name, [
|
||||
'jonny',
|
||||
]);
|
||||
return $user->name === 'jonny';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ class RouteServiceProvider extends ServiceProvider
|
|||
* Configure the rate limiters for the application.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function configureRateLimiting()
|
||||
{
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Laravel\Telescope\IncomingEntry;
|
||||
use Laravel\Telescope\Telescope;
|
||||
use Laravel\Telescope\TelescopeApplicationServiceProvider;
|
||||
|
||||
class TelescopeServiceProvider extends TelescopeApplicationServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
Telescope::night();
|
||||
|
||||
$this->hideSensitiveRequestDetails();
|
||||
|
||||
Telescope::filter(function (IncomingEntry $entry) {
|
||||
if ($this->app->isLocal()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $entry->isReportableException() ||
|
||||
$entry->isFailedJob() ||
|
||||
$entry->isScheduledTask() ||
|
||||
$entry->hasMonitoredTag();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent sensitive request details from being logged by Telescope.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function hideSensitiveRequestDetails()
|
||||
{
|
||||
if ($this->app->isLocal()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Telescope::hideRequestParameters(['_token']);
|
||||
|
||||
Telescope::hideRequestHeaders([
|
||||
'cookie',
|
||||
'x-csrf-token',
|
||||
'x-xsrf-token',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the Telescope gate.
|
||||
*
|
||||
* This gate determines who can access Telescope in non-local environments.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function gate()
|
||||
{
|
||||
Gate::define('viewTelescope', function ($user) {
|
||||
return in_array($user->name, [
|
||||
'jonny',
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -79,11 +79,12 @@ class BookmarkService
|
|||
}
|
||||
|
||||
/**
|
||||
* Given a URL, use browsershot to save an image of the page.
|
||||
* Given a URL, use `browsershot` to save an image of the page.
|
||||
*
|
||||
* @param string $url
|
||||
* @return string The uuid for the screenshot
|
||||
* @throws CouldNotTakeBrowsershot
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function saveScreenshot(string $url): string
|
||||
{
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
"ext-intl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-dom": "*",
|
||||
"cviebrock/eloquent-sluggable": "^8.0",
|
||||
"fideloper/proxy": "~4.0",
|
||||
"cviebrock/eloquent-sluggable": "^9.0",
|
||||
"fruitcake/laravel-cors": "^2.0",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"indieauth/client": "^1.1",
|
||||
|
@ -22,32 +21,29 @@
|
|||
"jonnybarnes/indieweb": "~0.2",
|
||||
"jonnybarnes/webmentions-parser": "~0.5",
|
||||
"jublonet/codebird-php": "4.0.0-beta.1",
|
||||
"laravel/framework": "^8.0",
|
||||
"laravel/framework": "^9.0",
|
||||
"laravel/horizon": "^5.0",
|
||||
"laravel/scout": "^8.0",
|
||||
"laravel/telescope": "^4.0",
|
||||
"laravel/tinker": "^2.0",
|
||||
"lcobucci/jwt": "^4.0",
|
||||
"league/commonmark": "^1.0",
|
||||
"league/flysystem-aws-s3-v3": "^1.0",
|
||||
"league/commonmark": "^2.0",
|
||||
"league/flysystem-aws-s3-v3": "^3.0",
|
||||
"mf2/mf2": "~0.3",
|
||||
"pmatseykanets/laravel-scout-postgres": "^7.3",
|
||||
"predis/predis": "~1.0",
|
||||
"spatie/browsershot": "~3.0",
|
||||
"spatie/commonmark-highlighter": "^2.0",
|
||||
"spatie/commonmark-highlighter": "^3.0",
|
||||
"tgalopin/html-sanitizer": "^1.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "^3.0",
|
||||
"barryvdh/laravel-ide-helper": "^2.6",
|
||||
"beyondcode/laravel-dump-server": "^1.0",
|
||||
"facade/ignition": "^2.3.6",
|
||||
"fakerphp/faker": "^1.9.2",
|
||||
"laravel/dusk": "^6.0",
|
||||
"mockery/mockery": "^1.0",
|
||||
"nunomaduro/collision": "^5.0",
|
||||
"nunomaduro/collision": "^6.1",
|
||||
"phpunit/php-code-coverage": "^9.2",
|
||||
"phpunit/phpunit": "^9.0",
|
||||
"spatie/laravel-ignition": "^1.0",
|
||||
"spatie/laravel-ray": "^1.12",
|
||||
"vimeo/psalm": "^4.0"
|
||||
},
|
||||
|
|
4037
composer.lock
generated
4037
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -220,7 +220,6 @@ return [
|
|||
App\Providers\EventServiceProvider::class,
|
||||
App\Providers\RouteServiceProvider::class,
|
||||
App\Providers\HorizonServiceProvider::class,
|
||||
App\Providers\TelescopeServiceProvider::class,
|
||||
|
||||
],
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ return [
|
|||
'charset' => 'utf8',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'schema' => 'public',
|
||||
'search_path' => 'public',
|
||||
'sslmode' => 'prefer',
|
||||
],
|
||||
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Search Engine
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default search connection that gets used while
|
||||
| using Laravel Scout. This connection is used when syncing all models
|
||||
| to the search service. You should adjust this based on your needs.
|
||||
|
|
||||
| Supported: "algolia", "elasticsearch", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'driver' => env('SCOUT_DRIVER'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Index Prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify a prefix that will be applied to all search index
|
||||
| names used by Scout. This prefix may be useful if you have multiple
|
||||
| "tenants" or applications sharing the same search infrastructure.
|
||||
|
|
||||
*/
|
||||
|
||||
'prefix' => env('SCOUT_PREFIX', ''),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queue Data Syncing
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows you to control if the operations that sync your data
|
||||
| with your search engines are queued. When this is set to "true" then
|
||||
| all automatic data syncing will get queued for better performance.
|
||||
|
|
||||
*/
|
||||
|
||||
'queue' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Algolia Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure your Algolia settings. Algolia is a cloud hosted
|
||||
| search engine which works great with Scout out of the box. Just plug
|
||||
| in your application ID and admin API key to get started searching.
|
||||
|
|
||||
*/
|
||||
|
||||
'algolia' => [
|
||||
'id' => env('ALGOLIA_APP_ID', ''),
|
||||
'secret' => env('ALGOLIA_SECRET', ''),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Elasticsearch Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure your settings for Elasticsearch, which is a
|
||||
| distributed, open source search and analytics engine. Feel free
|
||||
| to add as many Elasticsearch servers as required by your app.
|
||||
|
|
||||
*/
|
||||
|
||||
'elasticsearch' => [
|
||||
'index' => env('ELASTICSEARCH_INDEX', 'laravel'),
|
||||
|
||||
'config' => [
|
||||
'hosts' => [
|
||||
env('ELASTICSEARCH_HOST', 'localhost'),
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'pgsql' => [
|
||||
'connection' => env('DB_CONNECTION', 'pgsql'),
|
||||
// You may want to update index documents directly in PostgreSQL (i.e. via triggers).
|
||||
// In this case you can set this value to false.
|
||||
'maintain_index' => true,
|
||||
],
|
||||
|
||||
];
|
|
@ -1,155 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Laravel\Telescope\Watchers;
|
||||
use Laravel\Telescope\Http\Middleware\Authorize;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the subdomain where Telescope will be accessible from. If the
|
||||
| setting is null, Telescope will reside under the same domain as the
|
||||
| application. Otherwise, this value will be used as the subdomain.
|
||||
|
|
||||
*/
|
||||
|
||||
'domain' => null,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the URI path where Telescope will be accessible from. Feel free
|
||||
| to change this path to anything you like. Note that the URI will not
|
||||
| affect the paths of its internal API that aren't exposed to users.
|
||||
|
|
||||
*/
|
||||
|
||||
'path' => 'telescope',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Storage Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This configuration options determines the storage driver that will
|
||||
| be used to store Telescope's data. In addition, you may set any
|
||||
| custom options as needed by the particular driver you choose.
|
||||
|
|
||||
*/
|
||||
|
||||
'driver' => env('TELESCOPE_DRIVER', 'database'),
|
||||
|
||||
'storage' => [
|
||||
'database' => [
|
||||
'connection' => env('DB_CONNECTION', 'mysql'),
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Master Switch
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option may be used to disable all Telescope watchers regardless
|
||||
| of their individual configuration, which simply provides a single
|
||||
| and convenient way to enable or disable Telescope data storage.
|
||||
|
|
||||
*/
|
||||
|
||||
'enabled' => env('TELESCOPE_ENABLED', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Route Middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These middleware will be assigned to every Telescope route, giving you
|
||||
| the chance to add your own middleware to this list or change any of
|
||||
| the existing middleware. Or, you can simply stick with this list.
|
||||
|
|
||||
*/
|
||||
|
||||
'middleware' => [
|
||||
'web',
|
||||
Authorize::class,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Ignored Paths & Commands
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following array lists the URI paths and Artisan commands that will
|
||||
| not be watched by Telescope. In addition to this list, some Laravel
|
||||
| commands, like migrations and queue commands, are always ignored.
|
||||
|
|
||||
*/
|
||||
|
||||
'ignore_paths' => [
|
||||
//
|
||||
],
|
||||
|
||||
'ignore_commands' => [
|
||||
//
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Watchers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following array lists the "watchers" that will be registered with
|
||||
| Telescope. The watchers gather the application's profile data when
|
||||
| a request or task is executed. Feel free to customize this list.
|
||||
|
|
||||
*/
|
||||
|
||||
'watchers' => [
|
||||
Watchers\CacheWatcher::class => env('TELESCOPE_CACHE_WATCHER', true),
|
||||
|
||||
Watchers\CommandWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_COMMAND_WATCHER', true),
|
||||
'ignore' => [],
|
||||
],
|
||||
|
||||
Watchers\DumpWatcher::class => env('TELESCOPE_DUMP_WATCHER', true),
|
||||
Watchers\EventWatcher::class => env('TELESCOPE_EVENT_WATCHER', true),
|
||||
Watchers\ExceptionWatcher::class => env('TELESCOPE_EXCEPTION_WATCHER', true),
|
||||
Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true),
|
||||
Watchers\LogWatcher::class => env('TELESCOPE_LOG_WATCHER', true),
|
||||
Watchers\MailWatcher::class => env('TELESCOPE_MAIL_WATCHER', true),
|
||||
|
||||
Watchers\ModelWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_MODEL_WATCHER', true),
|
||||
'events' => ['eloquent.*'],
|
||||
],
|
||||
|
||||
Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true),
|
||||
|
||||
Watchers\QueryWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_QUERY_WATCHER', true),
|
||||
'ignore_packages' => true,
|
||||
'slow' => 100,
|
||||
],
|
||||
|
||||
Watchers\RedisWatcher::class => env('TELESCOPE_REDIS_WATCHER', true),
|
||||
|
||||
Watchers\RequestWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_REQUEST_WATCHER', true),
|
||||
'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64),
|
||||
],
|
||||
|
||||
Watchers\GateWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_GATE_WATCHER', true),
|
||||
'ignore_abilities' => [],
|
||||
'ignore_packages' => true,
|
||||
],
|
||||
|
||||
Watchers\ScheduleWatcher::class => env('TELESCOPE_SCHEDULE_WATCHER', true),
|
||||
],
|
||||
];
|
|
@ -24,7 +24,7 @@ class WebMentionFactory extends Factory
|
|||
return [
|
||||
'source' => $this->faker->url,
|
||||
'target' => url('notes/1'),
|
||||
'type' => 'reply',
|
||||
'type' => 'in-reply-to',
|
||||
'content' => $this->faker->paragraph,
|
||||
];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('notes', function (Blueprint $table) {
|
||||
DB::statement('DROP INDEX IF EXISTS notes_searchable_index');
|
||||
DB::statement('ALTER TABLE notes DROP searchable');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('notes', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
};
|
3393
package-lock.json
generated
3393
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -6,7 +6,7 @@
|
|||
"license": "CC0-1.0",
|
||||
"dependencies": {
|
||||
"normalize.css": "^8.0.1",
|
||||
"puppeteer": "^13.0.1"
|
||||
"puppeteer": "^14.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.3",
|
||||
|
@ -27,8 +27,8 @@
|
|||
"postcss-loader": "^6.1.1",
|
||||
"pre-commit": "^1.1.3",
|
||||
"stylelint": "^14.2.0",
|
||||
"stylelint-config-standard": "^24.0.0",
|
||||
"stylelint-webpack-plugin": "^2.1.1",
|
||||
"stylelint-config-standard": "^25.0.0",
|
||||
"stylelint-webpack-plugin": "^3.1.1",
|
||||
"webpack": "^5.3.2",
|
||||
"webpack-cli": "^4.0.0"
|
||||
},
|
||||
|
|
2
public/assets/app.css
vendored
2
public/assets/app.css
vendored
|
@ -1,6 +1,6 @@
|
|||
/*!***************************************************************************************************************************************************************************!*\
|
||||
!*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[0].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[0].use[2]!./resources/css/app.css ***!
|
||||
\***************************************************************************************************************************************************************************/
|
||||
:root{--font-stack-body:"Whitney SSm A","Whitney SSm B",sans-serif;--font-stack-headings:"Quarto A","Quarto B",serif;--font-stack-monospace:"Operator Mono SSm A","Operator Mono SSm B",monospace;--color-background:#004643;--color-headline:#fffffe;--color-paragraph:#abd1c6;--color-button:#f9bc60;--color-button-text:#001e1d;--color-stroke:#001e1d;--color-main:#e8e4e6;--color-highlight:#f9bc60;--color-secondary:#abd1c6;--color-tertiary:#e16162}body{-webkit-box-orient:vertical;-webkit-box-direction:normal;background-color:var(--color-background);color:var(--color-paragraph);display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;font-family:var(--font-stack-body);font-size:2rem;font-style:normal;font-weight:400}h1,h2,h3,h4,h5,h6{font-family:var(--font-stack-headings);font-style:normal;font-weight:800}code,pre{font-family:var(--font-stack-monospace);font-style:normal;font-weight:400}a{color:var(--color-highlight);text-decoration:none}.h-feed>.h-entry,.h-feed>.note{margin-top:4rem}main{-webkit-box-orient:vertical;-webkit-box-direction:normal;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;margin:auto}main img{max-width:100%}main .h-entry:first-child>.bookmark-link{padding-top:2rem}.note{-webkit-box-orient:vertical;-ms-flex-direction:column;flex-direction:column}.note,.note-metadata{-webkit-box-direction:normal;display:-webkit-box;display:-ms-flexbox;display:flex}.note-metadata{-webkit-box-orient:horizontal;-webkit-box-pack:justify;-ms-flex-pack:justify;-ms-flex-direction:row;flex-direction:row;justify-content:space-between}.note .client{word-break:break-all}.note .syndication-links svg{height:1em;width:1em}.note>.e-content>.naked-link .u-photo{margin:2rem 0}article header>h1{margin-bottom:0}.post-info{font-size:1.4rem}.pagination{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;justify-content:space-evenly;list-style-type:none;max-width:90vw}.personal-bio{padding:0 2rem}footer{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;margin-top:1.5rem}.iwc-logo{max-width:100%}#top-header{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-pack:center;-ms-flex-pack:center;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;justify-content:center}#top-header h1{text-align:center;width:100%}nav{-webkit-box-pack:center;-ms-flex-pack:center;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;justify-content:center}nav a{margin:0 .5rem}.post-info a,.syndication-links .u-syndication{text-decoration:none}.p-bridgy-facebook-content,.p-bridgy-twitter-content{display:none}@media screen and (max-width:699px){main{margin-left:5px;margin-right:5px}input{max-width:95vw}footer{margin-left:5px;margin-right:5px}}@media screen and (min-width:700px){main{max-width:700px}main>.h-entry,main>.note{padding:0 1rem}}
|
||||
:root{--font-stack-body:"Whitney SSm A","Whitney SSm B",sans-serif;--font-stack-headings:"Quarto A","Quarto B",serif;--font-stack-monospace:"Operator Mono SSm A","Operator Mono SSm B",monospace;--color-background:#004643;--color-headline:#fffffe;--color-paragraph:#abd1c6;--color-button:#f9bc60;--color-button-text:#001e1d;--color-stroke:#001e1d;--color-main:#e8e4e6;--color-highlight:#f9bc60;--color-secondary:#abd1c6;--color-tertiary:#e16162}body{-webkit-box-orient:vertical;-webkit-box-direction:normal;background-color:var(--color-background);color:var(--color-paragraph);display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;font-family:var(--font-stack-body);font-size:2rem;font-style:normal;font-weight:400}h1,h2,h3,h4,h5,h6{font-family:var(--font-stack-headings);font-style:normal;font-weight:800}code,pre{font-family:var(--font-stack-monospace);font-style:normal;font-weight:400}a{color:var(--color-highlight);text-decoration:none}.h-feed>.h-entry,.h-feed>.note{margin-top:4rem}main{-webkit-box-orient:vertical;-webkit-box-direction:normal;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;margin:auto}main img{max-width:100%}main .h-entry:first-child>.bookmark-link{padding-top:2rem}.note{-webkit-box-orient:vertical;-ms-flex-direction:column;flex-direction:column}.note,.note-metadata{-webkit-box-direction:normal;display:-webkit-box;display:-ms-flexbox;display:flex}.note-metadata{-webkit-box-orient:horizontal;-webkit-box-pack:justify;-ms-flex-pack:justify;-ms-flex-direction:row;flex-direction:row;justify-content:space-between}.note .client{word-break:break-all}.note .syndication-links svg{height:1em;width:1em}.note>.e-content>.naked-link .u-photo{margin:2rem 0}article header>h1{margin-bottom:0}.post-info{font-size:1.4rem}.pagination{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;justify-content:space-evenly;list-style-type:none;max-width:90vw}.personal-bio{padding:0 2rem}footer{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;margin-top:1.5rem}.iwc-logo{max-width:100%}#top-header{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-box-pack:center;-ms-flex-pack:center;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;justify-content:center}#top-header h1{text-align:center;width:100%}nav{-webkit-box-pack:center;-ms-flex-pack:center;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;justify-content:center}nav a{margin:0 .5rem}.post-info a,.syndication-links .u-syndication{text-decoration:none}.hovercard,.p-bridgy-facebook-content,.p-bridgy-twitter-content{display:none}@media screen and (max-width:699px){main{margin-left:5px;margin-right:5px}input{max-width:95vw}footer{margin-left:5px;margin-right:5px}}@media screen and (min-width:700px){main{max-width:700px}main>.h-entry,main>.note{padding:0 1rem}}
|
||||
|
||||
/*# sourceMappingURL=app.css.map*/
|
Binary file not shown.
1
resources/css/app.css
vendored
1
resources/css/app.css
vendored
|
@ -3,3 +3,4 @@
|
|||
@import "layout/main.css";
|
||||
@import "link-style.css";
|
||||
@import "posse.css";
|
||||
@import "user-profiles.css";
|
||||
|
|
3
resources/css/user-profiles.css
vendored
Normal file
3
resources/css/user-profiles.css
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
.hovercard {
|
||||
display: none;
|
||||
}
|
|
@ -26,7 +26,7 @@
|
|||
@endforeach
|
||||
</div>
|
||||
|
||||
{{ $items->links() }}
|
||||
{{ $items->links('templates.pagination') }}
|
||||
|
||||
@include('templates.bio')
|
||||
@stop
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<html lang="en-GB">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>@if (App::environment() == 'local'){!! "[testing] -"!!}@endif @yield('title'){{ config('app.display_name') }}</title>
|
||||
<title>@yield('title'){{ config('app.display_name') }}</title>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<link rel="stylesheet" href="/assets/frontend/normalize.css">
|
||||
@if (!empty(config('app.font_link')))<link rel="stylesheet" href="{{ config('app.font_link') }}">@endif
|
||||
|
@ -48,9 +48,9 @@
|
|||
</main>
|
||||
|
||||
<footer>
|
||||
<form action="search" method="get">
|
||||
<input type="text" name="terms" title="Search"><button type="submit">Search</button>
|
||||
</form>
|
||||
{{-- <form action="search" method="get">--}}
|
||||
{{-- <input type="text" name="terms" title="Search"><button type="submit">Search</button>--}}
|
||||
{{-- </form>--}}
|
||||
<p>Built with love: <a href="/colophon">Colophon</a></p>
|
||||
<a href="https://indieweb.org"><img src="/assets/img/iwc.svg" alt="Indie Web Camp logo" class="iwc-logo"></a>
|
||||
</footer>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
<ul>
|
||||
<li>I keep in touch with friends on <a rel="me" href="https://www.facebook.com/jonnybarnes" class="u-url">Facebook</a></li>
|
||||
<li>I follow people I find interesting on <a rel="me" href="https://twitter.com/jonnybarnes" class="u-url">Twitter</a></li>
|
||||
<li>I toot on the fediverse with my own instance of <a rel="me" href="https://mastodon.thebeeches.house/@jonny">Mastodon</a></li>
|
||||
<li>I push code to <a rel="me" href="https://github.com/jonnybarnes" class="u-url">GitHub</a></li>
|
||||
<li>I scrobble songs to <a rel="me" href="https://last.fm/user/jonnymbarnes" class="u-url">last.fm</a> that I listen to on <a rel="me" href="https://open.spotify.com/user/jonnybarnes89" class="u-url">Spotify</a></li>
|
||||
<li>I post photos to <a rel="me" href="https://www.instagram.com/jonnybarnes/">Instagram</a></li>
|
||||
|
|
25
resources/views/templates/pagination.blade.php
Normal file
25
resources/views/templates/pagination.blade.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
@if ($paginator->hasPages())
|
||||
<nav role="navigation">
|
||||
<div>
|
||||
@if ($paginator->onFirstPage())
|
||||
<span>
|
||||
{!! __('pagination.previous') !!}
|
||||
</span>
|
||||
@else
|
||||
<a href="{{ $paginator->previousPageUrl() }}">
|
||||
{!! __('pagination.previous') !!}
|
||||
</a>
|
||||
@endif
|
||||
|
||||
@if ($paginator->hasMorePages())
|
||||
<a href="{{ $paginator->nextPageUrl() }}">
|
||||
{!! __('pagination.next') !!}
|
||||
</a>
|
||||
@else
|
||||
<span>
|
||||
{!! __('pagination.next') !!}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</nav>
|
||||
@endif
|
|
@ -183,8 +183,6 @@ Route::group(['domain' => config('url.longurl')], function () {
|
|||
// Places
|
||||
Route::get('places', [PlacesController::class, 'index']);
|
||||
Route::get('places/{place}', [PlacesController::class, 'show']);
|
||||
|
||||
Route::get('search', [SearchController::class, 'search']);
|
||||
});
|
||||
|
||||
// Short URL
|
||||
|
|
|
@ -25,6 +25,19 @@ class ActivityStreamTest extends TestCase
|
|||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function notesPageContainsAuthorActivityStreamData(): void
|
||||
{
|
||||
$response = $this->get('/notes', ['Accept' => 'application/activity+json']);
|
||||
$response->assertHeader('Content-Type', 'application/activity+json');
|
||||
$response->assertJson([
|
||||
'@context' => 'https://www.w3.org/ns/activitystreams',
|
||||
'id' => config('app.url'),
|
||||
'type' => 'Person',
|
||||
'name' => config('user.displayname'),
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function requestForNoteIncludesActivityStreamData(): void
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Tests\Feature\Admin;
|
||||
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AdminTest extends TestCase
|
||||
|
@ -31,4 +32,51 @@ class AdminTest extends TestCase
|
|||
]);
|
||||
$response->assertRedirect('/login');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function loginSucceeds(): void
|
||||
{
|
||||
User::factory([
|
||||
'name' => 'admin',
|
||||
'password' => bcrypt('password'),
|
||||
])->create();
|
||||
|
||||
$response = $this->post('/login', [
|
||||
'name' => 'admin',
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$response->assertRedirect('/');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function whenLoggedInRedirectsToAdminPage(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$response = $this->actingAs($user)->get('/login');
|
||||
$response->assertRedirect('/');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function loggedOutUsersSimplyRedirected(): void
|
||||
{
|
||||
$response = $this->get('/logout');
|
||||
$response->assertRedirect('/');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function loggedInUsersShownLogoutForm(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$response = $this->actingAs($user)->get('/logout');
|
||||
$response->assertViewIs('logout');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function loggedInUsersCanLogout(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$response = $this->actingAs($user)->post('/logout');
|
||||
$response->assertRedirect('/');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ class ContactsTest extends TestCase
|
|||
$file = fopen(__DIR__ . '/../../aaron.png', 'rb');
|
||||
$mock = new MockHandler([
|
||||
new Response(200, ['Content-Type' => 'text/html'], $html),
|
||||
new Response(200, ['Content-Type' => 'iamge/png'], $file),
|
||||
new Response(200, ['Content-Type' => 'image/png'], $file),
|
||||
]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
|
|
33
tests/Feature/FrontPageTest.php
Normal file
33
tests/Feature/FrontPageTest.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Article;
|
||||
use App\Models\Bookmark;
|
||||
use App\Models\Like;
|
||||
use App\Models\Note;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class FrontPageTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
/** @test */
|
||||
public function frontPageLoadsAllContent(): void
|
||||
{
|
||||
Note::factory()->create(['note' => 'Note 1']);
|
||||
Article::factory()->create(['title' => 'Article 1']);
|
||||
Bookmark::factory()->create(['url' => 'https://example.com']);
|
||||
Like::factory()->create([
|
||||
'url' => 'https://example.org/1',
|
||||
'content' => 'Like 1',
|
||||
]);
|
||||
|
||||
$this->get('/')
|
||||
->assertSee('Note 1')
|
||||
->assertSee('Article 1')
|
||||
->assertSee('https://example.com')
|
||||
->assertSee('Like 1');
|
||||
}
|
||||
}
|
28
tests/Feature/HorizonTest.php
Normal file
28
tests/Feature/HorizonTest.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Tests\TestCase;
|
||||
|
||||
class HorizonTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Horizon has its own test suite, here we just test it has been installed successfully.
|
||||
*
|
||||
* @test
|
||||
* @return void
|
||||
*/
|
||||
public function horizonIsInstalled(): void
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'name' => 'jonny',
|
||||
]);
|
||||
|
||||
$response = $this->actingAs($user)->get('/horizon');
|
||||
|
||||
$response->assertStatus(200);
|
||||
}
|
||||
}
|
|
@ -233,6 +233,44 @@ class LikesTest extends TestCase
|
|||
$this->assertEquals('Jonny Barnes', Like::find($id)->author_name);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function noErrorForFailureToPosseWithBridgy(): void
|
||||
{
|
||||
$like = new Like();
|
||||
$like->url = 'https://twitter.com/jonnybarnes/status/1050823255123251200';
|
||||
$like->save();
|
||||
$id = $like->id;
|
||||
|
||||
$job = new ProcessLike($like);
|
||||
|
||||
$mock = new MockHandler([
|
||||
new Response(404, [], 'Not found'),
|
||||
]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
$this->app->bind(Client::class, function () use ($client) {
|
||||
return $client;
|
||||
});
|
||||
|
||||
$info = (object) [
|
||||
'author_name' => 'Jonny Barnes',
|
||||
'author_url' => 'https://twitter.com/jonnybarnes',
|
||||
'html' => '<div>HTML of the tweet embed</div>',
|
||||
];
|
||||
$codebirdMock = $this->getMockBuilder(Codebird::class)
|
||||
->addMethods(['statuses_oembed'])
|
||||
->getMock();
|
||||
$codebirdMock->method('statuses_oembed')
|
||||
->willReturn($info);
|
||||
$this->app->instance(Codebird::class, $codebirdMock);
|
||||
|
||||
$authorship = new Authorship();
|
||||
|
||||
$job->handle($client, $authorship);
|
||||
|
||||
$this->assertEquals('Jonny Barnes', Like::find($id)->author_name);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function unknownLikeGivesNotFoundResponse(): void
|
||||
{
|
||||
|
|
|
@ -34,6 +34,50 @@ class MicropubMediaTest extends TestCase
|
|||
$response->assertJson(['url' => null]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function getRequestWithInvalidTokenReturnsErrorResponse(): void
|
||||
{
|
||||
$response = $this->get(
|
||||
'/api/media?q=last',
|
||||
['HTTP_Authorization' => 'Bearer abc123']
|
||||
);
|
||||
$response->assertStatus(400);
|
||||
$response->assertJsonFragment(['error_description' => 'The provided token did not pass validation']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function getRequestWithTokenWithoutScopeReturnsErrorResponse(): void
|
||||
{
|
||||
$response = $this->get(
|
||||
'/api/media?q=last',
|
||||
['HTTP_Authorization' => 'Bearer ' . $this->getTokenWithNoScope()]
|
||||
);
|
||||
$response->assertStatus(400);
|
||||
$response->assertJsonFragment(['error_description' => 'The provided token has no scopes']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function getRequestWithTokenWithInsufficientScopeReturnsErrorResponse(): void
|
||||
{
|
||||
$response = $this->get(
|
||||
'/api/media?q=last',
|
||||
['HTTP_Authorization' => 'Bearer ' . $this->getTokenWithIncorrectScope()]
|
||||
);
|
||||
$response->assertStatus(401);
|
||||
$response->assertJsonFragment(['error_description' => 'The token’s scope does not have the necessary requirements.']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function emptyGetRequestWithTokenReceivesOkResponse(): void
|
||||
{
|
||||
$response = $this->get(
|
||||
'/api/media',
|
||||
['HTTP_Authorization' => 'Bearer ' . $this->getToken()]
|
||||
);
|
||||
$response->assertStatus(200);
|
||||
$response->assertJson(['status' => 'OK']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function clientCanListLastUpload(): void
|
||||
{
|
||||
|
@ -124,6 +168,22 @@ class MicropubMediaTest extends TestCase
|
|||
unlink(storage_path('app/') . $filename);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function mediaEndpointUploadRequiresFile(): void
|
||||
{
|
||||
$response = $this->post(
|
||||
'/api/media',
|
||||
[],
|
||||
['HTTP_Authorization' => 'Bearer ' . $this->getToken()]
|
||||
);
|
||||
$response->assertStatus(400);
|
||||
$response->assertJson([
|
||||
'response' => 'error',
|
||||
'error' => 'invalid_request',
|
||||
'error_description' => 'No file was sent with the request',
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function errorResponseForUnknownQValue(): void
|
||||
{
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Note;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SearchControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
/** @test */
|
||||
public function searchPageReturnsResult(): void
|
||||
{
|
||||
Note::factory()->create([
|
||||
'note' => 'I love [duckduckgo.com](https://duckduckgo.com)',
|
||||
]);
|
||||
$response = $this->get('/search?terms=love');
|
||||
$response->assertSee('duckduckgo.com');
|
||||
}
|
||||
}
|
|
@ -79,5 +79,12 @@ class ArticlesTest extends TestCase
|
|||
|
||||
$emptyScope = Article::date()->get();
|
||||
$this->assertCount(2, $emptyScope);
|
||||
|
||||
// Check the December case
|
||||
$article = Article::factory()->create([
|
||||
'created_at' => Carbon::now()->setMonth(12)->toDateTimeString(),
|
||||
'updated_at' => Carbon::now()->setMonth(12)->toDateTimeString(),
|
||||
]);
|
||||
$this->assertCount(1, Article::date(date('Y'), 12)->get());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,23 +89,25 @@ class ProcessWebMentionJobTest extends TestCase
|
|||
Queue::fake();
|
||||
|
||||
$parser = new Parser();
|
||||
$note = Note::factory()->create();
|
||||
$source = 'https://aaronpk.localhost/reply/1';
|
||||
WebMention::factory()->create([
|
||||
'source' => $source,
|
||||
'target' => $note->longurl,
|
||||
]);
|
||||
|
||||
$html = <<<HTML
|
||||
<div class="h-entry">
|
||||
<p>In reply to <a class="u-in-reply-to" href="/notes/E">a note</a></p>
|
||||
<p>In reply to <a class="u-in-reply-to" href="{$note->longurl}">a note</a></p>
|
||||
<div class="e-content">Updated reply</div>
|
||||
</div>
|
||||
HTML;
|
||||
$html = str_replace('href="', 'href="' . config('app.url'), $html);
|
||||
$mock = new MockHandler([
|
||||
new Response(200, [], $html),
|
||||
]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
|
||||
$note = Note::factory()->create();
|
||||
$source = 'https://aaronpk.localhost/reply/1';
|
||||
|
||||
$job = new ProcessWebMention($note, $source);
|
||||
$job->handle($parser, $client);
|
||||
|
||||
|
@ -114,7 +116,7 @@ class ProcessWebMentionJobTest extends TestCase
|
|||
'source' => $source,
|
||||
'type' => 'in-reply-to',
|
||||
// phpcs:ignore Generic.Files.LineLength.TooLong
|
||||
'mf2' => '{"rels": [], "items": [{"type": ["h-entry"], "properties": {"content": [{"html": "Updated reply", "value": "Updated reply"}], "in-reply-to": ["' . config('app.url') . '/notes/E"]}}], "rel-urls": []}',
|
||||
'mf2' => '{"rels": [], "items": [{"type": ["h-entry"], "properties": {"content": [{"html": "Updated reply", "value": "Updated reply"}], "in-reply-to": ["' . $note->longurl . '"]}}], "rel-urls": []}',
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,17 @@ class LikesTest extends TestCase
|
|||
$this->assertEquals('some plaintext content', $like->content);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function weCanHandleBlankContent(): void
|
||||
{
|
||||
$like = new Like();
|
||||
$like->url = 'https://example.org/post/123';
|
||||
$like->content = null;
|
||||
$like->save();
|
||||
|
||||
$this->assertNull($like->content);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function htmlLikeContentIsFiltered(): void
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue