mirror of
https://github.com/Kovah/LinkAce.git
synced 2025-04-14 03:32:01 +02:00
commit
85461ae4b9
@ -39,7 +39,7 @@ class ImportHtmlBookmarks
|
||||
}
|
||||
|
||||
if ($generateMeta) {
|
||||
$linkMeta = HtmlMeta::getFromUrl($link['uri']);
|
||||
$linkMeta = (new HtmlMeta)->getFromUrl($link['uri']);
|
||||
$title = $link['title'] ?: $linkMeta['title'];
|
||||
$description = $link['note'] ?: $linkMeta['description'];
|
||||
} else {
|
||||
|
@ -8,7 +8,7 @@ use Venturecraft\Revisionable\Revision;
|
||||
|
||||
class CleanupLinkHistoriesCommand extends Command
|
||||
{
|
||||
protected $signature = 'link:cleanup-histories {field?}';
|
||||
protected $signature = 'links:cleanup-histories {field?}';
|
||||
|
||||
protected $description = 'Removes all but the last 5 entries in the link histories.
|
||||
{field : If provided, only history entries of that field are deleted}';
|
||||
|
51
app/Console/Commands/UpdateLinkThumbnails.php
Normal file
51
app/Console/Commands/UpdateLinkThumbnails.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Helper\HtmlMeta;
|
||||
use App\Models\Link;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class UpdateLinkThumbnails extends Command
|
||||
{
|
||||
protected $signature = 'links:update-thumbnails';
|
||||
|
||||
protected $description = 'Updates the thumbnails for all existing links, done in batches.';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$this->confirm('This command updates the thumbnail for all links with the status "ok". This can take a long time, depending on the amount of links you have saved. Do you want to proceed?');
|
||||
|
||||
$totalCount = Link::where('status', Link::STATUS_OK)->count();
|
||||
$processedLinks = 0;
|
||||
|
||||
if ($totalCount === 0) {
|
||||
$this->warn('No links with status "ok" found. Aborting');
|
||||
}
|
||||
|
||||
$this->comment("Started processing of $totalCount links...");
|
||||
|
||||
Link::where('status', Link::STATUS_OK)->latest()
|
||||
->chunk(100, function ($links) use ($processedLinks, $totalCount) {
|
||||
foreach ($links as $link) {
|
||||
$this->updateThumbnailForLink($link);
|
||||
sleep(1); // Rate limiting of outgoing traffic
|
||||
}
|
||||
|
||||
$processedLinks += count($links);
|
||||
$this->comment("Processed $processedLinks of $totalCount links.");
|
||||
});
|
||||
|
||||
$this->info('Finished processing all links.');
|
||||
}
|
||||
|
||||
protected function updateThumbnailForLink(Link $link): void
|
||||
{
|
||||
$meta = (new HtmlMeta)->getFromUrl($link->url);
|
||||
|
||||
if ($meta['thumbnail'] !== null) {
|
||||
$link->thumbnail = $meta['thumbnail'];
|
||||
$link->save();
|
||||
}
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ use App\Console\Commands\CleanupLinkHistoriesCommand;
|
||||
use App\Console\Commands\RegisterUserCommand;
|
||||
use App\Console\Commands\ResetPasswordCommand;
|
||||
use App\Console\Commands\ImportCommand;
|
||||
use App\Console\Commands\UpdateLinkThumbnails;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
||||
@ -28,6 +29,7 @@ class Kernel extends ConsoleKernel
|
||||
ResetPasswordCommand::class,
|
||||
CleanupLinkHistoriesCommand::class,
|
||||
ImportCommand::class,
|
||||
UpdateLinkThumbnails::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -8,8 +8,14 @@ use Kovah\HtmlMeta\Exceptions\UnreachableUrlException;
|
||||
|
||||
class HtmlMeta
|
||||
{
|
||||
/** @var string */
|
||||
protected $url;
|
||||
|
||||
/** @var array */
|
||||
protected static $fallback;
|
||||
protected $fallback;
|
||||
|
||||
/** @var array */
|
||||
protected $meta;
|
||||
|
||||
/**
|
||||
* Get the title and description of an URL.
|
||||
@ -25,60 +31,99 @@ class HtmlMeta
|
||||
* @param bool $flashAlerts
|
||||
* @return array
|
||||
*/
|
||||
public static function getFromUrl(string $url, bool $flashAlerts = false): array
|
||||
public function getFromUrl(string $url, bool $flashAlerts = false): array
|
||||
{
|
||||
self::buildFallback($url);
|
||||
$this->url = $url;
|
||||
$this->buildFallback();
|
||||
|
||||
try {
|
||||
$meta = \Kovah\HtmlMeta\Facades\HtmlMeta::forUrl($url);
|
||||
$this->meta = \Kovah\HtmlMeta\Facades\HtmlMeta::forUrl($url);
|
||||
} catch (InvalidUrlException $e) {
|
||||
Log::warning($url . ': ' . $e->getMessage());
|
||||
if ($flashAlerts) {
|
||||
flash(trans('link.added_connection_error'), 'warning');
|
||||
}
|
||||
return self::$fallback;
|
||||
return $this->fallback;
|
||||
} catch (UnreachableUrlException $e) {
|
||||
Log::warning($url . ': ' . $e->getMessage());
|
||||
if ($flashAlerts) {
|
||||
flash(trans('link.added_request_error'), 'warning');
|
||||
}
|
||||
return self::$fallback;
|
||||
return $this->fallback;
|
||||
}
|
||||
|
||||
return self::buildLinkMeta($meta);
|
||||
return $this->buildLinkMeta();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a response array containing the link meta including a success flag.
|
||||
*
|
||||
* @param array $metaTags
|
||||
* @return array
|
||||
*/
|
||||
protected static function buildLinkMeta(array $metaTags): array
|
||||
protected function buildLinkMeta(): array
|
||||
{
|
||||
$metaTags['description'] = $metaTags['description']
|
||||
?? $metaTags['og:description']
|
||||
?? $metaTags['twitter:description']
|
||||
$this->meta['description'] = $this->meta['description']
|
||||
?? $this->meta['og:description']
|
||||
?? $this->meta['twitter:description']
|
||||
?? null;
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'title' => $metaTags['title'] ?? self::$fallback['title'],
|
||||
'description' => $metaTags['description'],
|
||||
'title' => $this->meta['title'] ?? $this->fallback['title'],
|
||||
'description' => $this->meta['description'],
|
||||
'thumbnail' => $this->getThumbnail(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The fallback is used in case of errors while trying to get the link meta.
|
||||
*
|
||||
* @param string $url
|
||||
*/
|
||||
protected static function buildFallback(string $url): void
|
||||
protected function buildFallback(): void
|
||||
{
|
||||
self::$fallback = [
|
||||
$this->fallback = [
|
||||
'success' => false,
|
||||
'title' => parse_url($url, PHP_URL_HOST) ?? $url,
|
||||
'title' => parse_url($this->url, PHP_URL_HOST) ?? $this->url,
|
||||
'description' => false,
|
||||
'thumbnail' => null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get the thumbnail from the meta tags and handle specific cases where we know how to get a proper image
|
||||
* from the website.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function getThumbnail(): ?string
|
||||
{
|
||||
$thumbnail = $this->meta['og:image']
|
||||
?? $this->meta['twitter:image']
|
||||
?? null;
|
||||
|
||||
if (!is_null($thumbnail) && parse_url($thumbnail, PHP_URL_HOST) === null) {
|
||||
// If the thumbnail does not contain the domain, add it in front of it
|
||||
$urlInfo = parse_url($this->url);
|
||||
$baseUrl = sprintf('%s://%s/', $urlInfo['scheme'], $urlInfo['host']);
|
||||
$thumbnail = $baseUrl . trim($thumbnail, '/');
|
||||
}
|
||||
|
||||
/*
|
||||
* Edge case of Youtube only (because of Youtube EU cookie consent)
|
||||
* Formula based on https://stackoverflow.com/a/2068371, returns Youtube image url
|
||||
* https://img.youtube.com/vi/[video-id]/mqdefault.jpg
|
||||
*/
|
||||
if (is_null($thumbnail)) {
|
||||
if (str_contains($this->url, 'youtube.com') && str_contains($this->url, 'v=')) {
|
||||
preg_match('/v=([a-zA-Z0-9]+)/', $this->url, $matched);
|
||||
$thumbnail = isset($matched[1]) ? 'https://img.youtube.com/vi/' . $matched[1] . '/mqdefault.jpg' : null;
|
||||
}
|
||||
|
||||
if (str_contains($this->url, 'youtu.be')) {
|
||||
preg_match('/youtu.be\/([a-zA-Z0-9_]+)/', $this->url, $matched);
|
||||
$thumbnail = isset($matched[1]) ? 'https://img.youtube.com/vi/' . $matched[1] . '/mqdefault.jpg' : null;
|
||||
}
|
||||
}
|
||||
|
||||
return $thumbnail;
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use Illuminate\Support\Facades\Storage;
|
||||
*/
|
||||
class UpdateHelper
|
||||
{
|
||||
protected static $releaseApiUrl = 'https://api.github.com/repos/kovah/linkace/releases';
|
||||
protected const RELEASE_API_URL = 'https://updates.linkace.org/api/current-version';
|
||||
|
||||
/**
|
||||
* Get the current version from the package.json file and cache it for a day.
|
||||
@ -71,14 +71,8 @@ class UpdateHelper
|
||||
*/
|
||||
protected static function getCurrentVersionFromAPI(): ?string
|
||||
{
|
||||
$response = Http::get(self::$releaseApiUrl);
|
||||
$response = Http::get(self::RELEASE_API_URL);
|
||||
|
||||
if (!$response->successful()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$releases = $response->json();
|
||||
|
||||
return $releases[0]['tag_name'] ?? null;
|
||||
return $response->successful() ? $response->body() : null;
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ function usersettings(string $key = '')
|
||||
* Retrieve system settings
|
||||
*
|
||||
* @param string $key
|
||||
* @return null|Collection
|
||||
* @return null|Collection|string
|
||||
*/
|
||||
function systemsettings(string $key = '')
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ class BookmarkletController extends Controller
|
||||
|
||||
session(['bookmarklet.create' => true]);
|
||||
|
||||
return view('actions.bookmarklet.create', [
|
||||
return view('app.bookmarklet.create', [
|
||||
'bookmark_url' => $newUrl,
|
||||
'bookmark_title' => $newTitle,
|
||||
'bookmark_description' => $newDescription,
|
||||
@ -56,7 +56,7 @@ class BookmarkletController extends Controller
|
||||
*/
|
||||
public function getCompleteView(): View
|
||||
{
|
||||
return view('actions.bookmarklet.complete');
|
||||
return view('app.bookmarklet.complete');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,6 +66,6 @@ class BookmarkletController extends Controller
|
||||
*/
|
||||
public function getLoginForm(): View
|
||||
{
|
||||
return view('actions.bookmarklet.login');
|
||||
return view('app.bookmarklet.login');
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ class ExportController extends Controller
|
||||
*/
|
||||
public function getExport(): View
|
||||
{
|
||||
return view('actions.export.export');
|
||||
return view('app.export.export');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -39,7 +39,7 @@ class ExportController extends Controller
|
||||
{
|
||||
$links = Link::orderBy('title', 'asc')->with('tags')->get();
|
||||
|
||||
$fileContent = view()->make('actions.export.html-export', ['links' => $links])->render();
|
||||
$fileContent = view()->make('app.export.html-export', ['links' => $links])->render();
|
||||
$fileName = config('app.name') . '_export.html';
|
||||
|
||||
return response()->streamDownload(function () use ($fileContent) {
|
||||
|
@ -21,7 +21,7 @@ class FeedController extends Controller
|
||||
'id' => $request->fullUrl(),
|
||||
];
|
||||
|
||||
return new Response(view('actions.feed.links', [
|
||||
return new Response(view('app.feed.links', [
|
||||
'meta' => $meta,
|
||||
'links' => $links,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
@ -37,7 +37,7 @@ class FeedController extends Controller
|
||||
'id' => $request->fullUrl(),
|
||||
];
|
||||
|
||||
return new Response(view('actions.feed.lists', [
|
||||
return new Response(view('app.feed.lists', [
|
||||
'meta' => $meta,
|
||||
'lists' => $lists,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
@ -53,7 +53,7 @@ class FeedController extends Controller
|
||||
'id' => $request->fullUrl(),
|
||||
];
|
||||
|
||||
return new Response(view('actions.feed.links', [
|
||||
return new Response(view('app.feed.links', [
|
||||
'meta' => $meta,
|
||||
'links' => $links,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
@ -69,7 +69,7 @@ class FeedController extends Controller
|
||||
'id' => $request->fullUrl(),
|
||||
];
|
||||
|
||||
return new Response(view('actions.feed.tags', [
|
||||
return new Response(view('app.feed.tags', [
|
||||
'meta' => $meta,
|
||||
'tags' => $tags,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
@ -85,7 +85,7 @@ class FeedController extends Controller
|
||||
'id' => $request->fullUrl(),
|
||||
];
|
||||
|
||||
return new Response(view('actions.feed.links', [
|
||||
return new Response(view('app.feed.links', [
|
||||
'meta' => $meta,
|
||||
'links' => $links,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
|
@ -18,7 +18,7 @@ class ImportController extends Controller
|
||||
*/
|
||||
public function getImport(): View
|
||||
{
|
||||
return view('actions.import.import');
|
||||
return view('app.import.import');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,7 +18,7 @@ class SearchController extends Controller
|
||||
*/
|
||||
public function getSearch(): View
|
||||
{
|
||||
return view('actions.search.search')
|
||||
return view('app.search.search')
|
||||
->with('results', collect([]))
|
||||
->with('order_by_options', $this->orderByOptions)
|
||||
->with('query_settings', [
|
||||
@ -46,7 +46,7 @@ class SearchController extends Controller
|
||||
$search = $this->buildDatabaseQuery($request);
|
||||
$results = $search->paginate(getPaginationLimit());
|
||||
|
||||
return view('actions.search.search')
|
||||
return view('app.search.search')
|
||||
->with('results', $results)
|
||||
->with('order_by_options', $this->orderByOptions)
|
||||
->with('query_settings', [
|
||||
|
@ -22,7 +22,7 @@ class SystemSettingsController extends Controller
|
||||
*/
|
||||
public function getSystemSettings(): View
|
||||
{
|
||||
return view('actions.settings.system', [
|
||||
return view('app.settings.system', [
|
||||
'linkaceVersion' => UpdateHelper::currentVersion(),
|
||||
]);
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ class TrashController extends Controller
|
||||
->byUser(auth()->id())
|
||||
->get();
|
||||
|
||||
return view('actions.trash.index', [
|
||||
return view('app.trash.index', [
|
||||
'links' => $links,
|
||||
'lists' => $lists,
|
||||
'tags' => $tags,
|
||||
|
@ -27,7 +27,7 @@ class UserSettingsController extends Controller
|
||||
{
|
||||
$bookmarkletCode = LinkAce::generateBookmarkletCode();
|
||||
|
||||
return view('actions.settings.user', [
|
||||
return view('app.settings.user', [
|
||||
'user' => auth()->user(),
|
||||
'bookmarklet_code' => $bookmarkletCode,
|
||||
]);
|
||||
|
@ -21,7 +21,7 @@ class FeedController extends Controller
|
||||
'id' => $request->fullUrl(),
|
||||
];
|
||||
|
||||
return new Response(view('actions.feed.links', [
|
||||
return new Response(view('app.feed.links', [
|
||||
'meta' => $meta,
|
||||
'links' => $links,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
@ -37,7 +37,7 @@ class FeedController extends Controller
|
||||
'id' => $request->fullUrl(),
|
||||
];
|
||||
|
||||
return new Response(view('actions.feed.lists', [
|
||||
return new Response(view('app.feed.lists', [
|
||||
'meta' => $meta,
|
||||
'lists' => $lists,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
@ -54,7 +54,7 @@ class FeedController extends Controller
|
||||
'id' => $request->fullUrl(),
|
||||
];
|
||||
|
||||
return new Response(view('actions.feed.links', [
|
||||
return new Response(view('app.feed.links', [
|
||||
'meta' => $meta,
|
||||
'links' => $links,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
@ -70,7 +70,7 @@ class FeedController extends Controller
|
||||
'id' => $request->fullUrl(),
|
||||
];
|
||||
|
||||
return new Response(view('actions.feed.tags', [
|
||||
return new Response(view('app.feed.tags', [
|
||||
'meta' => $meta,
|
||||
'tags' => $tags,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
@ -87,7 +87,7 @@ class FeedController extends Controller
|
||||
'id' => $request->fullUrl(),
|
||||
];
|
||||
|
||||
return new Response(view('actions.feed.links', [
|
||||
return new Response(view('app.feed.links', [
|
||||
'meta' => $meta,
|
||||
'links' => $links,
|
||||
]), 200, ['Content-Type' => 'application/xml']);
|
||||
|
@ -60,6 +60,7 @@ class Link extends Model
|
||||
'is_private',
|
||||
'status',
|
||||
'check_disabled',
|
||||
'thumbnail',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
|
@ -32,20 +32,20 @@ class LinkRepository
|
||||
*/
|
||||
public static function create(array $data, bool $flashAlerts = false): Link
|
||||
{
|
||||
$linkMeta = HtmlMeta::getFromUrl($data['url'], $flashAlerts);
|
||||
$linkMeta = (new HtmlMeta)->getFromUrl($data['url'], $flashAlerts);
|
||||
|
||||
$data['title'] = $data['title'] ?? $linkMeta['title'];
|
||||
$data['description'] = $data['description'] ?? $linkMeta['description'];
|
||||
$data['user_id'] = auth()->user()->id;
|
||||
$data['icon'] = LinkIconMapper::mapLink($data['url']);
|
||||
$data['thumbnail'] = $linkMeta['thumbnail'];
|
||||
|
||||
// If the meta helper was not successfull, disable future checks and set the status to broken
|
||||
// If the meta helper was not successful, disable future checks and set the status to broken
|
||||
if ($linkMeta['success'] === false) {
|
||||
$data['check_disabled'] = true;
|
||||
$data['status'] = Link::STATUS_BROKEN;
|
||||
}
|
||||
|
||||
/** @var Link $link */
|
||||
$link = Link::create($data);
|
||||
|
||||
self::processLinkTaxonomies($link, $data);
|
||||
@ -189,7 +189,7 @@ class LinkRepository
|
||||
/**
|
||||
* Tags or lists are passed as comma-delimited strings or integers.
|
||||
* If integers are passed we assume that the tags or lists are referenced
|
||||
* by their ID. n that case we try to reetrieve the tag or list by the
|
||||
* by their ID. n that case we try to retrieve the tag or list by the
|
||||
* provided ID.
|
||||
* If tags or lists are passed as strings, we create them and pass the new
|
||||
* entity to the taxonomy list.
|
||||
|
@ -115,7 +115,7 @@ class HistoryEntry extends Component
|
||||
*
|
||||
* @param $oldValue
|
||||
* @param $newValue
|
||||
* @return null[]
|
||||
* @return null[]|string[]
|
||||
*/
|
||||
protected function processTagsField($oldValue, $newValue)
|
||||
{
|
||||
|
208
composer.lock
generated
208
composer.lock
generated
@ -64,16 +64,16 @@
|
||||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.178.0",
|
||||
"version": "3.178.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "214e3d98c54277cd8965f1cf307dce39631407bf"
|
||||
"reference": "5a268a20272c0c9171570ed57f68b629e966deab"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/214e3d98c54277cd8965f1cf307dce39631407bf",
|
||||
"reference": "214e3d98c54277cd8965f1cf307dce39631407bf",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5a268a20272c0c9171570ed57f68b629e966deab",
|
||||
"reference": "5a268a20272c0c9171570ed57f68b629e966deab",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -148,9 +148,9 @@
|
||||
"support": {
|
||||
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.178.0"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.178.5"
|
||||
},
|
||||
"time": "2021-04-08T18:13:16+00:00"
|
||||
"time": "2021-04-15T18:12:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
@ -1835,16 +1835,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/fortify",
|
||||
"version": "v1.7.9",
|
||||
"version": "v1.7.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/fortify.git",
|
||||
"reference": "9ba71f3e448ae44370bdfe72f19952e23b4d6191"
|
||||
"reference": "82c99b6999f7e89f402cfd7eb4074e619382b3b7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/fortify/zipball/9ba71f3e448ae44370bdfe72f19952e23b4d6191",
|
||||
"reference": "9ba71f3e448ae44370bdfe72f19952e23b4d6191",
|
||||
"url": "https://api.github.com/repos/laravel/fortify/zipball/82c99b6999f7e89f402cfd7eb4074e619382b3b7",
|
||||
"reference": "82c99b6999f7e89f402cfd7eb4074e619382b3b7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1894,20 +1894,20 @@
|
||||
"issues": "https://github.com/laravel/fortify/issues",
|
||||
"source": "https://github.com/laravel/fortify"
|
||||
},
|
||||
"time": "2021-03-30T21:12:39+00:00"
|
||||
"time": "2021-04-13T15:05:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v8.36.2",
|
||||
"version": "v8.37.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "0debd8ad6b5aa1f61ccc73910adf049af4ca0444"
|
||||
"reference": "cf4082973abc796ec285190f0603380021f6d26f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/0debd8ad6b5aa1f61ccc73910adf049af4ca0444",
|
||||
"reference": "0debd8ad6b5aa1f61ccc73910adf049af4ca0444",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/cf4082973abc796ec285190f0603380021f6d26f",
|
||||
"reference": "cf4082973abc796ec285190f0603380021f6d26f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2062,7 +2062,7 @@
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2021-04-07T12:37:22+00:00"
|
||||
"time": "2021-04-13T13:49:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/commonmark",
|
||||
@ -2167,16 +2167,16 @@
|
||||
},
|
||||
{
|
||||
"name": "league/csv",
|
||||
"version": "9.7.0",
|
||||
"version": "9.7.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/csv.git",
|
||||
"reference": "4cacd9c72c4aa8bdbef43315b2ca25c46a0f833f"
|
||||
"reference": "0ec57e8264ec92565974ead0d1724cf1026e10c1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/csv/zipball/4cacd9c72c4aa8bdbef43315b2ca25c46a0f833f",
|
||||
"reference": "4cacd9c72c4aa8bdbef43315b2ca25c46a0f833f",
|
||||
"url": "https://api.github.com/repos/thephpleague/csv/zipball/0ec57e8264ec92565974ead0d1724cf1026e10c1",
|
||||
"reference": "0ec57e8264ec92565974ead0d1724cf1026e10c1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2247,7 +2247,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-03-26T22:08:10+00:00"
|
||||
"time": "2021-04-17T16:32:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/flysystem",
|
||||
@ -2780,16 +2780,16 @@
|
||||
},
|
||||
{
|
||||
"name": "opis/closure",
|
||||
"version": "3.6.1",
|
||||
"version": "3.6.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/opis/closure.git",
|
||||
"reference": "943b5d70cc5ae7483f6aff6ff43d7e34592ca0f5"
|
||||
"reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/opis/closure/zipball/943b5d70cc5ae7483f6aff6ff43d7e34592ca0f5",
|
||||
"reference": "943b5d70cc5ae7483f6aff6ff43d7e34592ca0f5",
|
||||
"url": "https://api.github.com/repos/opis/closure/zipball/06e2ebd25f2869e54a306dda991f7db58066f7f6",
|
||||
"reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2839,9 +2839,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/opis/closure/issues",
|
||||
"source": "https://github.com/opis/closure/tree/3.6.1"
|
||||
"source": "https://github.com/opis/closure/tree/3.6.2"
|
||||
},
|
||||
"time": "2020-11-07T02:01:34+00:00"
|
||||
"time": "2021-04-09T13:42:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/constant_time_encoding",
|
||||
@ -4492,16 +4492,16 @@
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-backup",
|
||||
"version": "6.15.1",
|
||||
"version": "6.16.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/spatie/laravel-backup.git",
|
||||
"reference": "94be6b3bb5248727367a50161be90e6c422558b4"
|
||||
"reference": "6b2229a07d92c2bb146ad9c5223fc32e9d74830c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-backup/zipball/94be6b3bb5248727367a50161be90e6c422558b4",
|
||||
"reference": "94be6b3bb5248727367a50161be90e6c422558b4",
|
||||
"url": "https://api.github.com/repos/spatie/laravel-backup/zipball/6b2229a07d92c2bb146ad9c5223fc32e9d74830c",
|
||||
"reference": "6b2229a07d92c2bb146ad9c5223fc32e9d74830c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4566,7 +4566,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/spatie/laravel-backup/issues",
|
||||
"source": "https://github.com/spatie/laravel-backup/tree/6.15.1"
|
||||
"source": "https://github.com/spatie/laravel-backup/tree/6.16.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -4578,7 +4578,7 @@
|
||||
"type": "other"
|
||||
}
|
||||
],
|
||||
"time": "2021-03-17T09:41:03+00:00"
|
||||
"time": "2021-04-15T09:31:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/temporary-directory",
|
||||
@ -7614,16 +7614,16 @@
|
||||
},
|
||||
{
|
||||
"name": "barryvdh/laravel-ide-helper",
|
||||
"version": "v2.9.3",
|
||||
"version": "v2.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/barryvdh/laravel-ide-helper.git",
|
||||
"reference": "2f61602e7a7f88ad29b0f71355b4bb71396e923b"
|
||||
"reference": "73b1012b927633a1b4cd623c2e6b1678e6faef08"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/2f61602e7a7f88ad29b0f71355b4bb71396e923b",
|
||||
"reference": "2f61602e7a7f88ad29b0f71355b4bb71396e923b",
|
||||
"url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/73b1012b927633a1b4cd623c2e6b1678e6faef08",
|
||||
"reference": "73b1012b927633a1b4cd623c2e6b1678e6faef08",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -7692,7 +7692,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/barryvdh/laravel-ide-helper/issues",
|
||||
"source": "https://github.com/barryvdh/laravel-ide-helper/tree/v2.9.3"
|
||||
"source": "https://github.com/barryvdh/laravel-ide-helper/tree/v2.10.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -7700,7 +7700,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-04-02T14:32:13+00:00"
|
||||
"time": "2021-04-09T06:17:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "barryvdh/reflection-docblock",
|
||||
@ -8072,43 +8072,6 @@
|
||||
],
|
||||
"time": "2021-03-25T17:01:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dnoegel/php-xdg-base-dir",
|
||||
"version": "v0.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dnoegel/php-xdg-base-dir.git",
|
||||
"reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd",
|
||||
"reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"XdgBaseDir\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "implementation of xdg base directory specification for php",
|
||||
"support": {
|
||||
"issues": "https://github.com/dnoegel/php-xdg-base-dir/issues",
|
||||
"source": "https://github.com/dnoegel/php-xdg-base-dir/tree/v0.1.1"
|
||||
},
|
||||
"time": "2019-12-04T15:06:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"version": "1.4.0",
|
||||
@ -8180,16 +8143,16 @@
|
||||
},
|
||||
{
|
||||
"name": "enlightn/enlightn",
|
||||
"version": "v1.21.0",
|
||||
"version": "v1.22.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/enlightn/enlightn.git",
|
||||
"reference": "959c9dc6d4dc95c6182569e96fc6e3c48ac538fc"
|
||||
"reference": "0958011684210838bb50646bedd6a33f73994e7c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/enlightn/enlightn/zipball/959c9dc6d4dc95c6182569e96fc6e3c48ac538fc",
|
||||
"reference": "959c9dc6d4dc95c6182569e96fc6e3c48ac538fc",
|
||||
"url": "https://api.github.com/repos/enlightn/enlightn/zipball/0958011684210838bb50646bedd6a33f73994e7c",
|
||||
"reference": "0958011684210838bb50646bedd6a33f73994e7c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -8257,9 +8220,9 @@
|
||||
"support": {
|
||||
"docs": "https://www.laravel-enlightn.com/docs/",
|
||||
"issues": "https://github.com/enlightn/enlightn/issues",
|
||||
"source": "https://github.com/enlightn/enlightn/tree/v1.21.0"
|
||||
"source": "https://github.com/enlightn/enlightn/tree/v1.22.0"
|
||||
},
|
||||
"time": "2021-03-23T07:38:44+00:00"
|
||||
"time": "2021-04-15T15:05:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "enlightn/security-checker",
|
||||
@ -8328,16 +8291,16 @@
|
||||
},
|
||||
{
|
||||
"name": "facade/flare-client-php",
|
||||
"version": "1.6.1",
|
||||
"version": "1.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/facade/flare-client-php.git",
|
||||
"reference": "f2b0969f2d9594704be74dbeb25b201570a98098"
|
||||
"reference": "6bf380035890cb0a09b9628c491ae3866b858522"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/facade/flare-client-php/zipball/f2b0969f2d9594704be74dbeb25b201570a98098",
|
||||
"reference": "f2b0969f2d9594704be74dbeb25b201570a98098",
|
||||
"url": "https://api.github.com/repos/facade/flare-client-php/zipball/6bf380035890cb0a09b9628c491ae3866b858522",
|
||||
"reference": "6bf380035890cb0a09b9628c491ae3866b858522",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -8381,7 +8344,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/facade/flare-client-php/issues",
|
||||
"source": "https://github.com/facade/flare-client-php/tree/1.6.1"
|
||||
"source": "https://github.com/facade/flare-client-php/tree/1.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -8389,20 +8352,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-04-08T08:50:01+00:00"
|
||||
"time": "2021-04-12T09:30:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "facade/ignition",
|
||||
"version": "2.8.2",
|
||||
"version": "2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/facade/ignition.git",
|
||||
"reference": "cb7f790e6306caeb4a9ffe21e59942b7128cc630"
|
||||
"reference": "a8201d51aae83addceaef9344592a3b068b5d64d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/facade/ignition/zipball/cb7f790e6306caeb4a9ffe21e59942b7128cc630",
|
||||
"reference": "cb7f790e6306caeb4a9ffe21e59942b7128cc630",
|
||||
"url": "https://api.github.com/repos/facade/ignition/zipball/a8201d51aae83addceaef9344592a3b068b5d64d",
|
||||
"reference": "a8201d51aae83addceaef9344592a3b068b5d64d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -8466,7 +8429,7 @@
|
||||
"issues": "https://github.com/facade/ignition/issues",
|
||||
"source": "https://github.com/facade/ignition"
|
||||
},
|
||||
"time": "2021-04-08T10:42:53+00:00"
|
||||
"time": "2021-04-09T20:45:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "facade/ignition-contracts",
|
||||
@ -9096,16 +9059,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nunomaduro/collision",
|
||||
"version": "v5.3.0",
|
||||
"version": "v5.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nunomaduro/collision.git",
|
||||
"reference": "aca63581f380f63a492b1e3114604e411e39133a"
|
||||
"reference": "41b7e9999133d5082700d31a1d0977161df8322a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nunomaduro/collision/zipball/aca63581f380f63a492b1e3114604e411e39133a",
|
||||
"reference": "aca63581f380f63a492b1e3114604e411e39133a",
|
||||
"url": "https://api.github.com/repos/nunomaduro/collision/zipball/41b7e9999133d5082700d31a1d0977161df8322a",
|
||||
"reference": "41b7e9999133d5082700d31a1d0977161df8322a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -9180,20 +9143,20 @@
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2021-01-25T15:34:13+00:00"
|
||||
"time": "2021-04-09T13:38:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nunomaduro/larastan",
|
||||
"version": "v0.7.2",
|
||||
"version": "v0.7.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nunomaduro/larastan.git",
|
||||
"reference": "cb7fa0b5af3738772e3568c0a0c7a080851e281d"
|
||||
"reference": "0ceef2a39b45be9d7f7dd96192a1721ba5112278"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nunomaduro/larastan/zipball/cb7fa0b5af3738772e3568c0a0c7a080851e281d",
|
||||
"reference": "cb7fa0b5af3738772e3568c0a0c7a080851e281d",
|
||||
"url": "https://api.github.com/repos/nunomaduro/larastan/zipball/0ceef2a39b45be9d7f7dd96192a1721ba5112278",
|
||||
"reference": "0ceef2a39b45be9d7f7dd96192a1721ba5112278",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -9257,7 +9220,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nunomaduro/larastan/issues",
|
||||
"source": "https://github.com/nunomaduro/larastan/tree/v0.7.2"
|
||||
"source": "https://github.com/nunomaduro/larastan/tree/v0.7.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -9277,7 +9240,7 @@
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2021-04-08T10:51:16+00:00"
|
||||
"time": "2021-04-16T08:25:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
@ -10098,20 +10061,19 @@
|
||||
},
|
||||
{
|
||||
"name": "psy/psysh",
|
||||
"version": "v0.10.7",
|
||||
"version": "v0.10.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bobthecow/psysh.git",
|
||||
"reference": "a395af46999a12006213c0c8346c9445eb31640c"
|
||||
"reference": "e4573f47750dd6c92dca5aee543fa77513cbd8d3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/a395af46999a12006213c0c8346c9445eb31640c",
|
||||
"reference": "a395af46999a12006213c0c8346c9445eb31640c",
|
||||
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/e4573f47750dd6c92dca5aee543fa77513cbd8d3",
|
||||
"reference": "e4573f47750dd6c92dca5aee543fa77513cbd8d3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"dnoegel/php-xdg-base-dir": "0.1.*",
|
||||
"ext-json": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"nikic/php-parser": "~4.0|~3.0|~2.0|~1.3",
|
||||
@ -10168,9 +10130,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/bobthecow/psysh/issues",
|
||||
"source": "https://github.com/bobthecow/psysh/tree/v0.10.7"
|
||||
"source": "https://github.com/bobthecow/psysh/tree/v0.10.8"
|
||||
},
|
||||
"time": "2021-03-14T02:14:56+00:00"
|
||||
"time": "2021-04-10T16:23:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "roave/security-advisories",
|
||||
@ -10178,12 +10140,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Roave/SecurityAdvisories.git",
|
||||
"reference": "aa48fe959b0236eede9c51a38f47df2bb81ef137"
|
||||
"reference": "593c4de369ca852cf3b86037f19435d47c136448"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/aa48fe959b0236eede9c51a38f47df2bb81ef137",
|
||||
"reference": "aa48fe959b0236eede9c51a38f47df2bb81ef137",
|
||||
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/593c4de369ca852cf3b86037f19435d47c136448",
|
||||
"reference": "593c4de369ca852cf3b86037f19435d47c136448",
|
||||
"shasum": ""
|
||||
},
|
||||
"conflict": {
|
||||
@ -10262,7 +10224,7 @@
|
||||
"friendsofsymfony/user-bundle": ">=1.2,<1.3.5",
|
||||
"friendsoftypo3/mediace": ">=7.6.2,<7.6.5",
|
||||
"fuel/core": "<1.8.1",
|
||||
"getgrav/grav": "<1.7-beta.8",
|
||||
"getgrav/grav": "<1.7.11",
|
||||
"getkirby/cms": ">=3,<3.4.5",
|
||||
"getkirby/panel": "<2.5.14",
|
||||
"gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3",
|
||||
@ -10300,6 +10262,9 @@
|
||||
"monolog/monolog": ">=1.8,<1.12",
|
||||
"moodle/moodle": "<3.5.17|>=3.7,<3.7.9|>=3.8,<3.8.8|>=3.9,<3.9.5|>=3.10,<3.10.2",
|
||||
"namshi/jose": "<2.2",
|
||||
"neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6",
|
||||
"neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.9.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3",
|
||||
"neos/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5",
|
||||
"nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6",
|
||||
"nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13",
|
||||
"nystudio107/craft-seomatic": "<3.3",
|
||||
@ -10346,6 +10311,7 @@
|
||||
"propel/propel1": ">=1,<=1.7.1",
|
||||
"pterodactyl/panel": "<0.7.19|>=1-rc.0,<=1-rc.6",
|
||||
"pusher/pusher-php-server": "<2.2.1",
|
||||
"pwweb/laravel-core": "<=0.3.6-beta",
|
||||
"rainlab/debugbar-plugin": "<3.1",
|
||||
"robrichards/xmlseclibs": "<3.0.4",
|
||||
"sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1",
|
||||
@ -10353,8 +10319,9 @@
|
||||
"scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11",
|
||||
"sensiolabs/connect": "<4.2.3",
|
||||
"serluck/phpwhois": "<=4.2.6",
|
||||
"shopware/core": "<=6.3.4",
|
||||
"shopware/platform": "<=6.3.5.1",
|
||||
"shopware/core": "<=6.3.5.2",
|
||||
"shopware/platform": "<=6.3.5.2",
|
||||
"shopware/production": "<=6.3.5.2",
|
||||
"shopware/shopware": "<5.6.9",
|
||||
"silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1",
|
||||
"silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2",
|
||||
@ -10431,9 +10398,10 @@
|
||||
"typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1",
|
||||
"typo3/cms-core": ">=6.2,<=6.2.56|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<9.5.25|>=10,<10.4.14|>=11,<11.1.1",
|
||||
"typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1",
|
||||
"typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5",
|
||||
"typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4",
|
||||
"typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6",
|
||||
"typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3",
|
||||
"typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1",
|
||||
"typo3/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5",
|
||||
"typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10",
|
||||
"ua-parser/uap-php": "<3.8",
|
||||
"usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2",
|
||||
@ -10511,7 +10479,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-04-09T08:01:23+00:00"
|
||||
"time": "2021-04-16T20:01:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
@ -42,6 +42,13 @@ return [
|
||||
* Determines if it should avoid unreadable folders.
|
||||
*/
|
||||
'ignore_unreadable_directories' => false,
|
||||
|
||||
/*
|
||||
* This path is used to make directories in resulting zip-file relative
|
||||
* Set to `null` to include complete absolute path
|
||||
* Example: base_path()
|
||||
*/
|
||||
'relative_path' => null,
|
||||
],
|
||||
|
||||
/*
|
||||
@ -92,6 +99,14 @@ return [
|
||||
*/
|
||||
'database_dump_compressor' => null,
|
||||
|
||||
/*
|
||||
* The file extension used for the database dump files.
|
||||
*
|
||||
* If not specified, the file extension will be .archive for MongoDB and .sql for all other databases
|
||||
* The file extension should be specified without a leading .
|
||||
*/
|
||||
'database_dump_file_extension' => '',
|
||||
|
||||
'destination' => [
|
||||
|
||||
/*
|
||||
@ -111,11 +126,26 @@ return [
|
||||
* The directory where the temporary files will be stored.
|
||||
*/
|
||||
'temporary_directory' => storage_path('app/backup-temp'),
|
||||
|
||||
/*
|
||||
* The password to be used for archive encryption.
|
||||
* Set to `null` to disable encryption.
|
||||
*/
|
||||
'password' => env('BACKUP_ARCHIVE_PASSWORD'),
|
||||
|
||||
/*
|
||||
* The encryption algorithm to be used for archive encryption.
|
||||
* You can set it to `null` or `false` to disable encryption.
|
||||
*
|
||||
* When set to 'default', we'll use ZipArchive::EM_AES_256 if it is
|
||||
* available on your system.
|
||||
*/
|
||||
'encryption' => 'default',
|
||||
],
|
||||
|
||||
/*
|
||||
* You can get notified when specific events occur. Out of the box you can use 'mail' and 'slack'.
|
||||
* For Slack you need to install guzzlehttp/guzzle and laravel/slack-notification-channel.
|
||||
* For Slack you need to install laravel/slack-notification-channel.
|
||||
*
|
||||
* You can also use your own notification classes, just make sure the class is named after one of
|
||||
* the `Spatie\Backup\Events` classes.
|
||||
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddThumbnailColumnToLinksTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('links', function (Blueprint $table) {
|
||||
$table->string('thumbnail', 255)->nullable()->default(null)->after('icon');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('links', function (Blueprint $table) {
|
||||
$table->dropColumn('thumbnail');
|
||||
});
|
||||
}
|
||||
}
|
22
package-lock.json
generated
22
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "linkace",
|
||||
"version": "1.5.0",
|
||||
"version": "1.6.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -3402,9 +3402,9 @@
|
||||
}
|
||||
},
|
||||
"csv-parse": {
|
||||
"version": "4.15.3",
|
||||
"resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.15.3.tgz",
|
||||
"integrity": "sha512-jlTqDvLdHnYMSr08ynNfk4IAUSJgJjTKy2U5CQBSu4cN9vQOJonLVZP4Qo4gKKrIgIQ5dr07UwOJdi+lRqT12w=="
|
||||
"version": "4.15.4",
|
||||
"resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.15.4.tgz",
|
||||
"integrity": "sha512-OdBbFc0yZhOm17lSxqkirrHlFFVpKRT0wp4DAGoJelsP3LbGzV9LNr7XmM/lrr0uGkCtaqac9UhP8PDHXOAbMg=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.1",
|
||||
@ -6687,9 +6687,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
"version": "8.2.9",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.9.tgz",
|
||||
"integrity": "sha512-b+TmuIL4jGtCHtoLi+G/PisuIl9avxs8IZMSmlABRwNz5RLUUACrC+ws81dcomz1nRezm5YPdXiMEzBEKgYn+Q==",
|
||||
"version": "8.2.10",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.10.tgz",
|
||||
"integrity": "sha512-b/h7CPV7QEdrqIxtAf2j31U5ef05uBDuvoXv6L51Q4rcS1jdlXAVKJv+atCFdUXYl9dyTHGyoMzIepwowRJjFw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"colorette": "^1.2.2",
|
||||
@ -9076,12 +9076,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"sass": {
|
||||
"version": "1.32.8",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.32.8.tgz",
|
||||
"integrity": "sha512-Sl6mIeGpzjIUZqvKnKETfMf0iDAswD9TNlv13A7aAF3XZlRPMq4VvJWBC2N2DXbp94MQVdNSFG6LfF/iOXrPHQ==",
|
||||
"version": "1.32.10",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.32.10.tgz",
|
||||
"integrity": "sha512-Nx0pcWoonAkn7CRp0aE/hket1UP97GiR1IFw3kcjV3pnenhWgZEWUf0ZcfPOV2fK52fnOcK3JdC/YYZ9E47DTQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chokidar": ">=2.0.0 <4.0.0"
|
||||
"chokidar": ">=3.0.0 <4.0.0"
|
||||
}
|
||||
},
|
||||
"sass-loader": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "linkace",
|
||||
"version": "1.5.0",
|
||||
"version": "1.6.0",
|
||||
"description": "A small, selfhosted bookmark manager with advanced features, built with Laravel and Docker",
|
||||
"homepage": "https://github.com/Kovah/LinkAce",
|
||||
"repository": {
|
||||
@ -14,8 +14,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"laravel-mix": "^6.0.16",
|
||||
"postcss": "^8.2.9",
|
||||
"sass": "^1.32.8",
|
||||
"postcss": "^8.2.10",
|
||||
"sass": "^1.32.10",
|
||||
"sass-loader": "^10.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
|
36
resources/assets/sass/custom/_app.scss
vendored
36
resources/assets/sass/custom/_app.scss
vendored
@ -165,3 +165,39 @@ code {
|
||||
#loader {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.link-thumbnail {
|
||||
box-shadow: inset 0 0 1px $secondary;
|
||||
}
|
||||
|
||||
.link-thumbnail-detail {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
padding-bottom: 52.5%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-size: cover;
|
||||
|
||||
@include media-breakpoint-up('lg') {
|
||||
width: 180px;
|
||||
height: 93px;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.link-thumbnail-list-holder {
|
||||
width: 180px;
|
||||
height: 93px;
|
||||
|
||||
//@include media-breakpoint-up('lg') {
|
||||
// width: 180px;
|
||||
//}
|
||||
|
||||
.link-thumbnail-list {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-size: cover !important;
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
@include('actions.settings.partials.system.updates')
|
||||
|
||||
@include('actions.settings.partials.system.cron')
|
||||
|
||||
@include('actions.settings.partials.system.general-settings')
|
||||
|
||||
@include('actions.settings.partials.system.guest-settings')
|
||||
|
||||
@endsection
|
@ -1,17 +0,0 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
@include('actions.settings.partials.user.bookmarklet')
|
||||
|
||||
@include('actions.settings.partials.user.api')
|
||||
|
||||
@include('actions.settings.partials.user.account-settings')
|
||||
|
||||
@include('actions.settings.partials.user.change-pw')
|
||||
|
||||
@include('actions.settings.partials.user.two-factor')
|
||||
|
||||
@include('actions.settings.partials.user.app-settings')
|
||||
|
||||
@endsection
|
@ -138,7 +138,7 @@
|
||||
@lang('search.no_results')
|
||||
</div>
|
||||
@else
|
||||
@include('actions.search.partials.table', ['results' => $results])
|
||||
@include('app.search.partials.table', ['results' => $results])
|
||||
@endif
|
||||
|
||||
</div>
|
@ -97,9 +97,9 @@
|
||||
<div class="col-12 col-sm-8 col-md-6"></div>
|
||||
</div>
|
||||
|
||||
@include('actions.settings.partials.system.guest.dark-mode')
|
||||
@include('app.settings.partials.system.guest.dark-mode')
|
||||
|
||||
@include('actions.settings.partials.system.guest.sharing')
|
||||
@include('app.settings.partials.system.guest.sharing')
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<x-icon.save class="mr-2"/> @lang('settings.save_settings')
|
@ -215,13 +215,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@include('actions.settings.partials.user.app-settings.archive-backups')
|
||||
@include('app.settings.partials.user.app-settings.archive-backups')
|
||||
|
||||
@include('actions.settings.partials.user.app-settings.privacy')
|
||||
@include('app.settings.partials.user.app-settings.privacy')
|
||||
|
||||
@include('actions.settings.partials.user.app-settings.dark-mode')
|
||||
@include('app.settings.partials.user.app-settings.dark-mode')
|
||||
|
||||
@include('actions.settings.partials.user.app-settings.sharing')
|
||||
@include('app.settings.partials.user.app-settings.sharing')
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<x-icon.save class="mr-2"/> @lang('settings.save_settings')
|
13
resources/views/app/settings/system.blade.php
Normal file
13
resources/views/app/settings/system.blade.php
Normal file
@ -0,0 +1,13 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
@include('app.settings.partials.system.updates')
|
||||
|
||||
@include('app.settings.partials.system.cron')
|
||||
|
||||
@include('app.settings.partials.system.general-settings')
|
||||
|
||||
@include('app.settings.partials.system.guest-settings')
|
||||
|
||||
@endsection
|
17
resources/views/app/settings/user.blade.php
Normal file
17
resources/views/app/settings/user.blade.php
Normal file
@ -0,0 +1,17 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
@include('app.settings.partials.user.bookmarklet')
|
||||
|
||||
@include('app.settings.partials.user.api')
|
||||
|
||||
@include('app.settings.partials.user.account-settings')
|
||||
|
||||
@include('app.settings.partials.user.change-pw')
|
||||
|
||||
@include('app.settings.partials.user.two-factor')
|
||||
|
||||
@include('app.settings.partials.user.app-settings')
|
||||
|
||||
@endsection
|
@ -25,7 +25,7 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
@includeWhen($links->isNotempty(), 'actions.trash.partials.link-table', ['links' => $links])
|
||||
@includeWhen($links->isNotempty(), 'app.trash.partials.link-table', ['links' => $links])
|
||||
@if($links->isEmpty())
|
||||
<small class="text-muted">@lang('trash.delete_no_entries')</small>
|
||||
@endif
|
||||
@ -50,7 +50,7 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
@includeWhen($lists->isNotEmpty(), 'actions.trash.partials.list-table', ['lists' => $lists])
|
||||
@includeWhen($lists->isNotEmpty(), 'app.trash.partials.list-table', ['lists' => $lists])
|
||||
@if($lists->isEmpty())
|
||||
<small class="text-muted">@lang('trash.delete_no_entries')</small>
|
||||
@endif
|
||||
@ -75,7 +75,7 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
@includeWhen($tags->isNotEmpty(), 'actions.trash.partials.tag-table', ['tags' => $tags])
|
||||
@includeWhen($tags->isNotEmpty(), 'app.trash.partials.tag-table', ['tags' => $tags])
|
||||
@if($tags->isEmpty())
|
||||
<small class="text-muted">@lang('trash.delete_no_entries')</small>
|
||||
@endif
|
||||
@ -100,7 +100,7 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
@includeWhen($notes->isNotEmpty(), 'actions.trash.partials.note-table', ['notes' => $notes])
|
||||
@includeWhen($notes->isNotEmpty(), 'app.trash.partials.note-table', ['notes' => $notes])
|
||||
|
||||
@if($notes->isEmpty())
|
||||
<small class="text-muted">@lang('trash.delete_no_entries')</small>
|
@ -1,7 +1,14 @@
|
||||
<div class="card mb-4">
|
||||
|
||||
<div class="card-header">
|
||||
<div class="d-flex align-items-top flex-wrap">
|
||||
<div class="d-flex align-items-top flex-wrap flex-md-nowrap">
|
||||
@if($link->thumbnail)
|
||||
<div class="d-flex justify-content-center mr-2 mb-2 mb-md-0 link-thumbnail-list-holder">
|
||||
<a href="{{ $link->url }}" {!! linkTarget() !!} class="rounded d-block link-thumbnail link-thumbnail-list"
|
||||
style="background-image: url('{{ $link->thumbnail }}');">
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
<div class="mr-2 mw-100">
|
||||
@if($link->is_private)
|
||||
<span>
|
||||
|
@ -7,7 +7,13 @@
|
||||
<div class="col-12 col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-sm-flex mb-3">
|
||||
<div class="d-flex flex-column flex-lg-row mb-3">
|
||||
@if($link->thumbnail)
|
||||
<a href="{{ $link->url }}" {!! linkTarget() !!}
|
||||
class="rounded d-block mt-lg-1 mr-lg-2 align-self-center link-thumbnail link-thumbnail-detail"
|
||||
style="background-image: url('{{ $link->thumbnail }}') ;">
|
||||
</a>
|
||||
@endif
|
||||
<div class="d-sm-inline-block mt-1 mb-2 mb-sm-0">
|
||||
{!! $link->getIcon('mr-1 mr-sm-2') !!}
|
||||
@if($link->is_private)
|
||||
|
@ -72,7 +72,7 @@ Route::group(['middleware' => ['auth']], function () {
|
||||
Route::resource('lists', ListController::class);
|
||||
Route::resource('tags', TagController::class);
|
||||
Route::resource('notes', NoteController::class)
|
||||
->except(['index', 'show']);
|
||||
->except(['index', 'show', 'create']);
|
||||
|
||||
Route::post('links/toggle-check/{link}', [LinkController::class, 'updateCheckToggle'])
|
||||
->name('links.toggle-check');
|
||||
|
@ -11,35 +11,33 @@ use Tests\TestCase;
|
||||
|
||||
class HtmlMetaHelperTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Test the titleFromURL() helper function with a valid URL
|
||||
* Will return the title of the DuckDuckGo frontpage: "DuckDuckGo"
|
||||
/*
|
||||
* Test the HtmlMeta helper with a regular website containing some meta information. Must properly return the
|
||||
* information extracted from the meta.
|
||||
*/
|
||||
public function testTitleFromValidURL(): void
|
||||
public function testMetaFromValidURL(): void
|
||||
{
|
||||
$testHtml = '<!DOCTYPE html><head>' .
|
||||
'<title>DuckDuckGo</title>' .
|
||||
'<meta name="test" content="Bla">' .
|
||||
'<meta name="description" content="This an example description">' .
|
||||
'<meta property="og:image" content="https://duckduckgo.com/assets/logo_social-media.png">' .
|
||||
'</head></html>';
|
||||
|
||||
Http::fake([
|
||||
'*' => Http::response($testHtml, 200),
|
||||
]);
|
||||
Http::fake(['*' => Http::response($testHtml)]);
|
||||
|
||||
$url = 'https://duckduckgo.com/';
|
||||
|
||||
$result = HtmlMeta::getFromUrl($url);
|
||||
$result = (new HtmlMeta)->getFromUrl($url);
|
||||
|
||||
$this->assertArrayHasKey('title', $result);
|
||||
$this->assertEquals('DuckDuckGo', $result['title']);
|
||||
$this->assertEquals('This an example description', $result['description']);
|
||||
$this->assertEquals('https://duckduckgo.com/assets/logo_social-media.png', $result['thumbnail']);
|
||||
$this->assertTrue($result['success']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the titleFromURL() helper function with a valid URL
|
||||
* Will return the title of the DuckDuckGo frontpage: "DuckDuckGo".
|
||||
/*
|
||||
* Test the HtmlMeta helper with an alternative description provided by the og:description tag.
|
||||
*/
|
||||
public function testAlternativeDescriptionFromValidURL(): void
|
||||
{
|
||||
@ -48,42 +46,81 @@ class HtmlMetaHelperTest extends TestCase
|
||||
'<meta property="og:description" content="This an example description">' .
|
||||
'</head></html>';
|
||||
|
||||
Http::fake([
|
||||
'*' => Http::response($testHtml, 200),
|
||||
]);
|
||||
Http::fake(['*' => Http::response($testHtml)]);
|
||||
|
||||
$url = 'https://duckduckgo.com/';
|
||||
|
||||
$result = HtmlMeta::getFromUrl($url);
|
||||
$result = (new HtmlMeta)->getFromUrl($url);
|
||||
|
||||
$this->assertArrayHasKey('title', $result);
|
||||
$this->assertEquals('DuckDuckGo', $result['title']);
|
||||
$this->assertEquals('This an example description', $result['description']);
|
||||
$this->assertTrue($result['success']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the titleFromURL() helper function with an invalid URL
|
||||
* Will return just the host of the given URL.
|
||||
public function testThumbnailWithoutHostFromValidURL(): void
|
||||
{
|
||||
$testHtml = '<!DOCTYPE html><head>' .
|
||||
'<meta property="og:image" content="/assets/logo_social-media.png">' .
|
||||
'</head></html>';
|
||||
|
||||
Http::fake(['*' => Http::response($testHtml)]);
|
||||
|
||||
$url = 'https://duckduckgo.com/about-us?utm_source=foo';
|
||||
|
||||
$result = (new HtmlMeta)->getFromUrl($url);
|
||||
|
||||
$this->assertEquals('https://duckduckgo.com/assets/logo_social-media.png', $result['thumbnail']);
|
||||
$this->assertTrue($result['success']);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the HtmlMeta helper with a YouTube link. Must return a special YouTube thumbnail.
|
||||
*/
|
||||
public function testYoutubeThumbnailFromValidURL(): void
|
||||
{
|
||||
$testHtml = '<!DOCTYPE html><head>' .
|
||||
'<title>YouTube</title>' .
|
||||
'</head></html>';
|
||||
|
||||
Http::fake(['*' => Http::response($testHtml)]);
|
||||
|
||||
// Regular YouTube link
|
||||
$url = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ';
|
||||
$result = (new HtmlMeta)->getFromUrl($url);
|
||||
|
||||
$this->assertArrayHasKey('title', $result);
|
||||
$this->assertEquals('YouTube', $result['title']);
|
||||
$this->assertEquals('https://img.youtube.com/vi/dQw4w9WgXcQ/mqdefault.jpg', $result['thumbnail']);
|
||||
$this->assertTrue($result['success']);
|
||||
|
||||
// Short Youtu.be sharing link
|
||||
$url = 'https://youtu.be/dQw4w9WgXcQ';
|
||||
$result = (new HtmlMeta)->getFromUrl($url);
|
||||
|
||||
$this->assertArrayHasKey('title', $result);
|
||||
$this->assertEquals('YouTube', $result['title']);
|
||||
$this->assertEquals('https://img.youtube.com/vi/dQw4w9WgXcQ/mqdefault.jpg', $result['thumbnail']);
|
||||
$this->assertTrue($result['success']);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the HtmlMeta helper with an invalid URL. Must return the hostname as the title.
|
||||
*/
|
||||
public function testTitleFromInvalidURL(): void
|
||||
{
|
||||
$url = 'https://duckduckgogo.comcom/';
|
||||
|
||||
Http::fake([
|
||||
'*' => Http::response(null, 404),
|
||||
]);
|
||||
Http::fake(['*' => Http::response('', 404)]);
|
||||
|
||||
$result = HtmlMeta::getFromUrl($url);
|
||||
$result = (new HtmlMeta)->getFromUrl($url);
|
||||
|
||||
$this->assertArrayHasKey('title', $result);
|
||||
$this->assertEquals('duckduckgogo.comcom', $result['title']);
|
||||
$this->assertFalse($result['success']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the titleFromURL() helper function with an invalid URL
|
||||
* Will return just the host of the given URL.
|
||||
/*
|
||||
* Test the HtmlMeta helper with an invalid URL. Must return the hostname as the title.
|
||||
*/
|
||||
public function testTitleFromUrlWithoutProtocol(): void
|
||||
{
|
||||
@ -93,17 +130,15 @@ class HtmlMetaHelperTest extends TestCase
|
||||
'*' => Http::response(null, 404),
|
||||
]);
|
||||
|
||||
$result = HtmlMeta::getFromUrl($url);
|
||||
$result = (new HtmlMeta)->getFromUrl($url);
|
||||
|
||||
$this->assertArrayHasKey('title', $result);
|
||||
$this->assertEquals('duckduckgo.com/about-us', $result['title']);
|
||||
$this->assertFalse($result['success']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the titleFromURL() helper function with an valid URL that returns
|
||||
* a certificate error.
|
||||
* Will return just the host of the given URL and issue a new flash message.
|
||||
/*
|
||||
* Test the HtmlMeta helper with an URL returning a certificate error. Must return the hostname as the title.
|
||||
*/
|
||||
public function testRequestError(): void
|
||||
{
|
||||
@ -116,7 +151,7 @@ class HtmlMetaHelperTest extends TestCase
|
||||
);
|
||||
});
|
||||
|
||||
$result = HtmlMeta::getFromUrl($url, true);
|
||||
$result = (new HtmlMeta)->getFromUrl($url, true);
|
||||
|
||||
$this->assertArrayHasKey('title', $result);
|
||||
$this->assertEquals('self-signed.badssl.com', $result['title']);
|
||||
@ -129,11 +164,9 @@ class HtmlMetaHelperTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the titleFromURL() helper function with an valid URL that is not
|
||||
* accessible due to connection errors, such as a refused connection for
|
||||
* a specific port.
|
||||
* Will return just the host of the given URL and issue a new flash message.
|
||||
/*
|
||||
* Test the HtmlMeta helper with an URL that is not accessible due to connection errors, such as a refused
|
||||
* connection for a specific port. Must return the hostname as the title.
|
||||
*/
|
||||
public function testConnectionError(): void
|
||||
{
|
||||
@ -145,7 +178,7 @@ class HtmlMetaHelperTest extends TestCase
|
||||
);
|
||||
});
|
||||
|
||||
$result = HtmlMeta::getFromUrl($url, true);
|
||||
$result = (new HtmlMeta)->getFromUrl($url, true);
|
||||
|
||||
$this->assertArrayHasKey('title', $result);
|
||||
$this->assertEquals('192.168.0.123', $result['title']);
|
||||
@ -171,13 +204,11 @@ class HtmlMetaHelperTest extends TestCase
|
||||
hex2bin('3c7469746c653ecfe8eae0e1f33c2f7469746c653e') .
|
||||
'</head></html>';
|
||||
|
||||
Http::fake([
|
||||
'*' => Http::response($testHtml, 200),
|
||||
]);
|
||||
Http::fake(['*' => Http::response($testHtml)]);
|
||||
|
||||
$url = 'https://duckduckgo.com/';
|
||||
|
||||
$result = HtmlMeta::getFromUrl($url);
|
||||
$result = (new HtmlMeta)->getFromUrl($url);
|
||||
|
||||
$this->assertArrayHasKey('title', $result);
|
||||
$this->assertEquals('Пикабу', $result['title']);
|
||||
@ -196,13 +227,11 @@ class HtmlMetaHelperTest extends TestCase
|
||||
hex2bin('3c7469746c653ecfe8eae0e1f33c2f7469746c653e') .
|
||||
'</head></html>';
|
||||
|
||||
Http::fake([
|
||||
'*' => Http::response($testHtml, 200),
|
||||
]);
|
||||
Http::fake(['*' => Http::response($testHtml)]);
|
||||
|
||||
$url = 'https://duckduckgo.com/';
|
||||
|
||||
$result = HtmlMeta::getFromUrl($url);
|
||||
$result = (new HtmlMeta)->getFromUrl($url);
|
||||
|
||||
$this->assertArrayHasKey('title', $result);
|
||||
$this->assertEquals('duckduckgo.com', $result['title']);
|
||||
@ -220,12 +249,10 @@ class HtmlMetaHelperTest extends TestCase
|
||||
'<meta charset="utf-8,windows-1251">' .
|
||||
'</head></html>';
|
||||
|
||||
Http::fake([
|
||||
'*' => Http::response($testHtml, 200),
|
||||
]);
|
||||
Http::fake(['*' => Http::response($testHtml)]);
|
||||
|
||||
$url = 'https://duckduckgo.com/';
|
||||
$result = HtmlMeta::getFromUrl($url);
|
||||
$result = (new HtmlMeta)->getFromUrl($url);
|
||||
|
||||
$this->assertArrayHasKey('title', $result);
|
||||
$this->assertEquals('duckduckgo.com', $result['title']);
|
||||
@ -253,7 +280,7 @@ class HtmlMetaHelperTest extends TestCase
|
||||
|
||||
$url = 'https://encoding-test.com/';
|
||||
|
||||
$result = HtmlMeta::getFromUrl($url);
|
||||
$result = (new HtmlMeta)->getFromUrl($url);
|
||||
|
||||
$this->assertArrayHasKey('description', $result);
|
||||
$this->assertEquals('Qualität', $result['description']);
|
||||
|
@ -16,10 +16,7 @@ class UpdateCheckTest extends TestCase
|
||||
public function testSuccessfulCheck(): void
|
||||
{
|
||||
Http::fake([
|
||||
'github.com/*' => Http::response(
|
||||
[['tag_name' => 'v100.0.0']],
|
||||
200
|
||||
),
|
||||
'*' => Http::response('v100.0.0'),
|
||||
]);
|
||||
|
||||
$result = UpdateHelper::checkForUpdates();
|
||||
@ -34,10 +31,7 @@ class UpdateCheckTest extends TestCase
|
||||
public function testSuccessfulCheckWithoutVersion(): void
|
||||
{
|
||||
Http::fake([
|
||||
'github.com/*' => Http::response(
|
||||
[['tag_name' => 'v0.0.0']],
|
||||
200
|
||||
),
|
||||
'*' => Http::response('v0.0.0'),
|
||||
]);
|
||||
|
||||
$result = UpdateHelper::checkForUpdates();
|
||||
@ -52,7 +46,7 @@ class UpdateCheckTest extends TestCase
|
||||
public function testUpdateCheckWithNetworkError(): void
|
||||
{
|
||||
Http::fake([
|
||||
'github.com/*' => Http::response([], 404),
|
||||
'*' => Http::response('', 404),
|
||||
]);
|
||||
|
||||
$result = UpdateHelper::checkForUpdates();
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
namespace Tests\Models;
|
||||
|
||||
use App\Helper\HtmlMeta;
|
||||
use App\Helper\LinkIconMapper;
|
||||
use App\Models\User;
|
||||
use App\Repositories\LinkRepository;
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
@ -23,11 +21,14 @@ class LinkCreateTest extends TestCase
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$testHtml = '<!DOCTYPE html><head><title>Google</title></head></html>';
|
||||
$testHtml = '<!DOCTYPE html><head>' .
|
||||
'<title>DuckDuckGo</title>' .
|
||||
'<meta name="test" content="Bla">' .
|
||||
'<meta name="description" content="This an example description">' .
|
||||
'<meta property="og:image" content="https://duckduckgo.com/assets/logo_social-media.png">' .
|
||||
'</head></html>';
|
||||
|
||||
Http::fake([
|
||||
'*' => Http::response($testHtml, 200),
|
||||
]);
|
||||
Http::fake(['*' => Http::response($testHtml)]);
|
||||
|
||||
$this->user = User::factory()->create();
|
||||
}
|
||||
@ -36,31 +37,32 @@ class LinkCreateTest extends TestCase
|
||||
{
|
||||
$this->be($this->user);
|
||||
|
||||
$url = 'https://google.com/';
|
||||
|
||||
$meta = HtmlMeta::getFromUrl($url);
|
||||
$url = 'https://duckduckgo.com/';
|
||||
|
||||
$originalData = [
|
||||
'url' => $url,
|
||||
'title' => $meta['title'],
|
||||
'description' => $meta['description'],
|
||||
'title' => null,
|
||||
'description' => null,
|
||||
'is_private' => false,
|
||||
];
|
||||
|
||||
$link = LinkRepository::create($originalData);
|
||||
|
||||
$automatedData = [
|
||||
$assertedData = [
|
||||
'id' => $link->id,
|
||||
'icon' => LinkIconMapper::mapLink($url),
|
||||
'user_id' => auth()->user()->id,
|
||||
'url' => $url,
|
||||
'title' => 'DuckDuckGo',
|
||||
'description' => 'This an example description',
|
||||
'icon' => 'link',
|
||||
'thumbnail' => 'https://duckduckgo.com/assets/logo_social-media.png',
|
||||
'is_private' => 0,
|
||||
'user_id' => 1,
|
||||
'status' => 1,
|
||||
'created_at' => $link->created_at,
|
||||
'updated_at' => $link->updated_at,
|
||||
'deleted_at' => null,
|
||||
];
|
||||
|
||||
$assertedData = array_merge($automatedData, $originalData);
|
||||
|
||||
$this->assertDatabaseHas('links', $assertedData);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user