1
0
mirror of https://github.com/Kovah/LinkAce.git synced 2025-04-21 23:42:10 +02:00

Large code cleanup and formatting

This commit is contained in:
Kovah 2022-07-20 10:54:53 +02:00
parent d37307785f
commit 8c9c0062d2
No known key found for this signature in database
GPG Key ID: AAAA031BA9830D7B
24 changed files with 49 additions and 213 deletions

View File

@ -15,13 +15,6 @@ class CreateNewUser implements CreatesNewUsers
{
use PasswordValidationRules;
/**
* Validate and create a newly registered user.
*
* @param array $input
* @return User
* @throws ValidationException
*/
public function create(array $input): User
{
Validator::make($input, self::rules())->validate();
@ -30,7 +23,6 @@ class CreateNewUser implements CreatesNewUsers
'name' => $input['name'],
'email' => $input['email'],
'password' => Hash::make($input['password']),
'api_token' => Str::random(32),
]);
(new SetDefaultSettingsForUser($user))->up();

View File

@ -6,11 +6,6 @@ use Laravel\Fortify\Rules\Password;
trait PasswordValidationRules
{
/**
* Get the validation rules used to validate passwords.
*
* @return array
*/
protected static function passwordRules(): array
{
return ['required', 'string', new Password, 'confirmed'];

View File

@ -11,13 +11,6 @@ class ResetUserPassword implements ResetsUserPasswords
{
use PasswordValidationRules;
/**
* Validate and reset the user's forgotten password.
*
* @param mixed $user
* @param array $input
* @throws ValidationException
*/
public function reset($user, array $input): void
{
Validator::make($input, [

View File

@ -11,13 +11,6 @@ class UpdateUserPassword implements UpdatesUserPasswords
{
use PasswordValidationRules;
/**
* Validate and update the user's password.
*
* @param mixed $user
* @param array $input
* @throws ValidationException
*/
public function update($user, array $input): void
{
Validator::make($input, [

View File

@ -11,13 +11,6 @@ use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
class UpdateUserProfileInformation implements UpdatesUserProfileInformation
{
/**
* Validate and update the given user's profile information.
*
* @param User $user
* @param array $input
* @throws ValidationException
*/
public function update($user, array $input): void
{
Validator::make($input, [
@ -32,6 +25,7 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
],
])->validateWithBag('updateProfileInformation');
// If the user must verify its email, handle the update accordingly
if ($input['email'] !== $user->email && $user instanceof MustVerifyEmail) {
$this->updateVerifiedUser($user, $input);
} else {
@ -42,12 +36,6 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
}
}
/**
* Update the given verified user's profile information.
*
* @param User $user
* @param array $input
*/
protected function updateVerifiedUser($user, array $input): void
{
$user->forceFill([

View File

@ -15,14 +15,6 @@ class ImportHtmlBookmarks
protected int $imported = 0;
protected int $skipped = 0;
/**
* Import all links from a given bookmarks file.
*
* @param string $data
* @param string $userId
* @param bool $generateMeta
* @return bool
*/
public function run(string $data, string $userId, bool $generateMeta = true): bool
{
$parser = new NetscapeBookmarkParser(logDir: storage_path('logs'));
@ -34,12 +26,6 @@ class ImportHtmlBookmarks
return false;
}
if (empty($links)) {
// This will never be reached at the moment because the bookmark parser is not capable of handling
// empty bookmarks exports. See https://github.com/shaarli/netscape-bookmark-parser/issues/50
return false;
}
foreach ($links as $link) {
if (Link::whereUrl($link['uri'])->first()) {
$this->skipped++;
@ -60,7 +46,7 @@ class ImportHtmlBookmarks
'url' => $link['uri'],
'title' => $title,
'description' => $description,
'icon' => LinkIconMapper::mapLink($link['uri']),
'icon' => LinkIconMapper::getIconForUrl($link['uri']),
'is_private' => $link['pub']
]);
$newLink->created_at = Carbon::createFromTimestamp($link['time']);

View File

@ -4,12 +4,5 @@ namespace App\Audits\Modifiers;
interface ModifierInterface
{
/**
* Modify an attribute value.
*
* @param mixed $value
*
* @return null|string
*/
public function modify(mixed $value): ?string;
}

View File

@ -6,7 +6,7 @@ use App\Models\User;
trait AsksForUser
{
protected User|null $user;
protected ?User $user;
protected function askForUser(): void
{

View File

@ -153,12 +153,6 @@ class CheckLinksCommand extends Command
}
}
/**
* Set the Link status to either moved or broken depending on the given
* status code.
*
* @param Link $link
*/
protected function processMovedLink(Link $link): void
{
$link->status = Link::STATUS_MOVED;
@ -168,12 +162,6 @@ class CheckLinksCommand extends Command
$this->movedLinks[] = $link;
}
/**
* Set the Link status to either moved or broken depending on the given
* status code.
*
* @param Link $link
*/
protected function processBrokenLink(Link $link): void
{
$link->status = Link::STATUS_BROKEN;
@ -183,13 +171,9 @@ class CheckLinksCommand extends Command
$this->brokenLinks[] = $link;
}
/**
* If the Link has not the "ok" status, set it to ok.
*
* @param Link $link
*/
protected function processWorkingLink(Link $link): void
{
// If the Link has not the "ok" status yet, set it to ok
if ($link->status !== Link::STATUS_OK) {
$link->status = Link::STATUS_OK;
$link->save();
@ -198,9 +182,6 @@ class CheckLinksCommand extends Command
$this->info(' Link looks okay.');
}
/**
* Send notification to the main user if not running from the console.
*/
protected function sendNotification(): void
{
if (empty($this->movedLinks) && empty($this->brokenLinks)) {
@ -208,6 +189,7 @@ class CheckLinksCommand extends Command
return;
}
// @TODO The user should be defined elsewhere, maybe in the config
Notification::send(
User::find(1),
new LinkCheckNotification($this->movedLinks, $this->brokenLinks)

View File

@ -22,7 +22,6 @@ class ImportCommand extends Command
{
$lookupMeta = true;
// Check if option "-skip-lookup" is present
if ($this->option('skip-meta-generation')) {
$this->info('Skipping automatic meta generation.');
$lookupMeta = false;
@ -47,7 +46,6 @@ class ImportCommand extends Command
return;
}
// Check if option "-skip-check" is present
if ($this->option('skip-check')) {
$this->info('Skipping link check.');
} elseif (config('mail.host') !== null) {

View File

@ -10,7 +10,6 @@ class ResetPasswordCommand extends Command
use AsksForUser;
protected $signature = 'reset-password';
protected $description = 'Reset the password for a given user without the need of configuring email sending.';
public function handle(): void

View File

@ -9,7 +9,6 @@ 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(): void

View File

@ -9,7 +9,6 @@ class ViewRecoveryCodesCommand extends Command
use AsksForUser;
protected $signature = '2fa:view-recovery-codes';
protected $description = 'View the recovery codes for a user, in case the user has no access to LinkAce anymore.';
public function handle(): void

View File

@ -3,34 +3,25 @@
namespace App\Console;
use App\Console\Commands\CheckLinksCommand;
use App\Console\Commands\CleanupLinkHistoriesCommand;
use App\Console\Commands\ImportCommand;
use App\Console\Commands\RegisterUserCommand;
use App\Console\Commands\ResetPasswordCommand;
use App\Console\Commands\UpdateLinkThumbnails;
use App\Console\Commands\ViewRecoveryCodesCommand;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
RegisterUserCommand::class,
CheckLinksCommand::class,
ResetPasswordCommand::class,
ImportCommand::class,
RegisterUserCommand::class,
ResetPasswordCommand::class,
UpdateLinkThumbnails::class,
ViewRecoveryCodesCommand::class,
];
/**
* Define the application's command schedule.
*
* @param Schedule $schedule
*/
protected function schedule(Schedule $schedule): void
{
$schedule->command('links:check')->hourly();
@ -44,9 +35,6 @@ class Kernel extends ConsoleKernel
}
}
/**
* Register the commands for the application.
*/
protected function commands(): void
{
$this->load(__DIR__ . '/Commands');

View File

@ -3,6 +3,7 @@
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Psr\Log\LogLevel;
use Throwable;
class Handler extends ExceptionHandler
@ -10,7 +11,7 @@ class Handler extends ExceptionHandler
/**
* A list of exception types with their corresponding custom log levels.
*
* @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
* @var array<class-string<Throwable>, LogLevel::*>
*/
protected $levels = [
//
@ -19,7 +20,7 @@ class Handler extends ExceptionHandler
/**
* A list of the exception types that are not reported.
*
* @var array<int, class-string<\Throwable>>
* @var array<int, class-string<Throwable>>
*/
protected $dontReport = [
//

View File

@ -3,7 +3,6 @@
namespace App\Helper;
use Illuminate\Support\Facades\Log;
use JetBrains\PhpStorm\ArrayShape;
use Kovah\HtmlMeta\Exceptions\InvalidUrlException;
use Kovah\HtmlMeta\Exceptions\UnreachableUrlException;
@ -52,11 +51,7 @@ class HtmlMeta
return $this->buildLinkMeta();
}
/**
* Build a response array containing the link meta including a success flag.
*
* @return array
*/
// Build a response array containing the link meta including a success flag.
protected function buildLinkMeta(): array
{
$this->meta['description'] ??= $this->meta['og:description']
@ -71,9 +66,7 @@ class HtmlMeta
];
}
/**
* The fallback is used in case of errors while trying to get the link meta.
*/
// The fallback is used in case of errors while trying to get the link meta.
protected function buildFallback(): void
{
$this->fallback = [
@ -85,8 +78,8 @@ class HtmlMeta
}
/**
* 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.
* 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
*/

View File

@ -90,13 +90,7 @@ class LinkIconMapper
'youtube\.com' => 'brand.youtube',
];
/**
* Check if the given url matches an icon
*
* @param string $url
* @return string
*/
public static function mapLink(string $url): string
public static function getIconForUrl(string $url): string
{
foreach (self::$iconMap as $pattern => $icon) {
if (preg_match('/' . $pattern . '/i', $url)) {

View File

@ -17,11 +17,6 @@ class Sharing
'#E-SHARETEXT#',
];
/**
* @param string $service
* @param Link $link
* @return string
*/
public static function getShareLink(string $service, Link $link): string
{
$serviceDetails = config('sharing.services.' . $service);
@ -39,12 +34,6 @@ class Sharing
]);
}
/**
* Prepare all needed raw or encoded values for the share link
*
* @param Link $link
* @return array
*/
protected static function generateLinkData(Link $link): array
{
$subject = $link->title ?: trans(config('sharing.defaults.subject'));
@ -54,21 +43,16 @@ class Sharing
return [
$link->url, // URL
self::encode($link->url), // endoced URL
self::encode($link->url), // encoded URL
$subject, // subject
self::encode($subject), // encoded subject
$shareText, // sharetext
self::encode($shareText), // encoded sharetext
$shareText, // share text
self::encode($shareText), // encoded share text
];
}
/**
* Encode a string with the basic rawurlencode function
* "Hello this is text!" becomes Hello%20this%20is%20text%21%
*
* @param string $string
* @return string
*/
// Encode a string with the basic rawurlencode function
// "Hello this is text!" becomes Hello%20this%20is%20text%21%
protected static function encode(string $string): string
{
return rawurlencode($string);

View File

@ -2,19 +2,12 @@
namespace App\Helper;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class WaybackMachine
{
public static string $baseUrl = 'https://web.archive.org';
/**
* Save a URL to the Wayback Machine
*
* @param string $url
* @return bool
*/
public static function saveToArchive(string $url): bool
{
if (!filter_var($url, FILTER_VALIDATE_URL)) {
@ -28,6 +21,7 @@ class WaybackMachine
try {
$response = $request->head($archiveUrl);
} catch (\Exception $e) {
// We ignore timeouts as the Archive may take quite a while to actually save the website
if (!str_contains($e->getMessage(), 'cURL error 28: Operation timed out')) {
Log::warning($archiveUrl . ': ' . $e->getMessage());
}
@ -44,12 +38,6 @@ class WaybackMachine
return true;
}
/**
* Get the link to the Wayback Machine archive for a specific URL
*
* @param string $url
* @return null|string
*/
public static function getArchiveLink(string $url): ?string
{
if (!filter_var($url, FILTER_VALIDATE_URL)) {

View File

@ -15,9 +15,9 @@ use Illuminate\Support\Facades\Log;
/**
* Check if the setup was completed.
*
* @return bool
* @return bool|null
*/
function setupCompleted()
function setupCompleted(): ?bool
{
try {
return systemsettings('setup_completed');
@ -28,7 +28,7 @@ function setupCompleted()
}
/**
* Shorthand for the current user settings
* Shorthand for the current user settings.
*
* @param string $key
* @param int|null $userId
@ -52,12 +52,12 @@ function usersettings(string $key = '', ?int $userId = null): mixed
}
/**
* Retrieve system settings
* Retrieve guest settings.
*
* @param string $key
* @return mixed
*/
function guestsettings(string $key = '')
function guestsettings(string $key = ''): mixed
{
if ($key === '') {
return app(GuestSettings::class)->toArray();
@ -67,12 +67,12 @@ function guestsettings(string $key = '')
}
/**
* Retrieve system settings
* Retrieve system settings.
*
* @param string $key
* @return mixed
*/
function systemsettings(string $key = '')
function systemsettings(string $key = ''): mixed
{
if ($key === '') {
return app(SystemSettings::class)->toArray();
@ -82,7 +82,7 @@ function systemsettings(string $key = '')
}
/**
* Output a correctly formatted date with the correct timezone
* Output a correctly formatted date with the correct timezone.
*
* @param CarbonInterface $date
* @param bool $use_relational
@ -110,7 +110,7 @@ function formatDateTime(CarbonInterface $date, bool $use_relational = false): st
}
/**
* Get the correct pagination limit
* Get the correct pagination limit.
*
* @return mixed
*/
@ -130,7 +130,7 @@ function getPaginationLimit(): mixed
}
/**
* Generate all share links for a link, but for enabled services only
* Generate all share links for a link, but for enabled services only.
*
* @param Link $link
* @return string
@ -159,7 +159,14 @@ function getShareLinks(Link $link): string
}
/**
* Build sorting links for a table column
* Build sorting links for a table column.
*
* @param string $label
* @param string $route
* @param string $type
* @param string $orderBy
* @param string $orderDir
* @return string
*/
function tableSorter(string $label, string $route, string $type, string $orderBy, string $orderDir): string
{
@ -186,20 +193,8 @@ function tableSorter(string $label, string $route, string $type, string $orderBy
}
/**
* Get the Wayback Machine link for a URL
*
* @param string|Link $link
* @return null|string
*/
function waybackLink(string|Link $link): ?string
{
$link = $link->url ?? $link;
return WaybackMachine::getArchiveLink($link);
}
/**
* Return proper link attributes based on the links_new_tab user setting
* Return proper link target attributes based on the links_new_tab user setting.
* noopener and noreferrer are added for security reasons.
*
* @return string
*/
@ -230,7 +225,7 @@ function escapeSearchQuery(string $query): string
}
/**
* Set up an HTTP request with a random user agent
* Set up an HTTP request with a random user agent.
*
* @param int $timeout
* @return PendingRequest

View File

@ -32,7 +32,7 @@ class LinkRepository
$data['title'] ??= $linkMeta['title'];
$data['description'] ??= $linkMeta['description'];
$data['user_id'] = auth()->user()->id;
$data['icon'] = LinkIconMapper::mapLink($data['url']);
$data['icon'] = LinkIconMapper::getIconForUrl($data['url']);
$data['thumbnail'] = $linkMeta['thumbnail'];
// If the meta helper was not successful, disable future checks and set the status to broken
@ -59,7 +59,7 @@ class LinkRepository
*/
public static function update(Link $link, array $data): Link
{
$data['icon'] = LinkIconMapper::mapLink($data['url'] ?? $link->url);
$data['icon'] = LinkIconMapper::getIconForUrl($data['url'] ?? $link->url);
$link->update($data);

View File

@ -61,6 +61,7 @@ class UserSettings extends Settings
self::$user_id = $user_id;
}
// By default, settings are scoped to the currently authenticated user
protected static function getUserId(): int
{
return self::$user_id ?: auth()->id();

View File

@ -72,7 +72,8 @@
</form>
<div class="mb-3">
<a href="{{ waybackLink($link) }}" class="btn btn-sm w-100 btn-outline-info" target="_blank">
<a href="{{ \App\Helper\WaybackMachine::getArchiveLink($link->url) }}"
class="btn btn-sm w-100 btn-outline-info" target="_blank">
@lang('link.wayback')
</a>
</div>

View File

@ -104,30 +104,4 @@ class HelperFunctionsTest extends TestCase
$this->assertEquals('100', $limit);
}
/**
* Test the saveToArchive() helper function with a valid URL.
* Should return true.
*/
public function testValidWaybackLink(): void
{
$expected = 'https://web.archive.org/web/*/' . $this->link->url;
$link = waybackLink($this->link);
$this->assertEquals($expected, $link);
}
/**
* Test the saveToArchive() helper function with an invalid URL.
* Will return false.
*/
public function testInvalidWaybackLink(): void
{
$url = 'not an URL';
$link = waybackLink($url);
$this->assertNull($link);
}
}