mirror of
https://github.com/Kovah/LinkAce.git
synced 2025-04-22 07:52:43 +02:00
Receive parsed keywords instead of fetched HTML for tag suggestions
This commit is contained in:
parent
31331bcd43
commit
3dc4a3d557
@ -10,6 +10,7 @@ use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Masterminds\HTML5;
|
||||
|
||||
class FetchController extends Controller
|
||||
{
|
||||
@ -121,9 +122,9 @@ class FetchController extends Controller
|
||||
* implementation.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function htmlForUrl(Request $request): Response
|
||||
public function htmlKeywordsFromUrl(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'url' => ['url'],
|
||||
@ -138,9 +139,20 @@ class FetchController extends Controller
|
||||
$response = $newRequest->get($url);
|
||||
|
||||
if ($response->successful()) {
|
||||
return response($response->body());
|
||||
$html5 = new HTML5();
|
||||
$dom = $html5->loadHTML($response->body());
|
||||
$keywords = [];
|
||||
/** @var \DOMElement $metaTag */
|
||||
foreach ($dom->getElementsByTagName('meta') as $metaTag) {
|
||||
if (strtolower($metaTag->getAttribute('name')) === 'keywords') {
|
||||
$keywords = explode(',', $metaTag->getAttributeNode('content')?->value);
|
||||
$keywords = array_map(fn($keyword) => trim(e($keyword)), $keywords);
|
||||
array_push($keywords, ...$keywords);
|
||||
}
|
||||
}
|
||||
return response()->json(['keywords' => $keywords]);
|
||||
}
|
||||
|
||||
return response(null);
|
||||
return response()->json(['keywords' => null]);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
"league/flysystem-aws-s3-v3": "^3.0",
|
||||
"league/flysystem-ftp": "^3.0",
|
||||
"league/flysystem-sftp-v3": "^3.0",
|
||||
"masterminds/html5": "^2.8",
|
||||
"predis/predis": "^v2.1",
|
||||
"rap2hpoutre/laravel-log-viewer": "^v2.2.0",
|
||||
"sentry/sentry-laravel": "^3.3.0",
|
||||
|
69
composer.lock
generated
69
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "3b677018795f662e7f84fe30e4c756e7",
|
||||
"content-hash": "3059bc7ac295710f1c4b0bda5470e66f",
|
||||
"packages": [
|
||||
{
|
||||
"name": "aws/aws-crt-php",
|
||||
@ -2946,6 +2946,73 @@
|
||||
],
|
||||
"time": "2022-04-17T13:12:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "masterminds/html5",
|
||||
"version": "2.8.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Masterminds/html5-php.git",
|
||||
"reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f47dcf3c70c584de14f21143c55d9939631bc6cf",
|
||||
"reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Masterminds\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Matt Butcher",
|
||||
"email": "technosophos@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Matt Farina",
|
||||
"email": "matt@mattfarina.com"
|
||||
},
|
||||
{
|
||||
"name": "Asmir Mustafic",
|
||||
"email": "goetas@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "An HTML5 parser and serializer.",
|
||||
"homepage": "http://masterminds.github.io/html5-php",
|
||||
"keywords": [
|
||||
"HTML5",
|
||||
"dom",
|
||||
"html",
|
||||
"parser",
|
||||
"querypath",
|
||||
"serializer",
|
||||
"xml"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Masterminds/html5-php/issues",
|
||||
"source": "https://github.com/Masterminds/html5-php/tree/2.8.1"
|
||||
},
|
||||
"time": "2023-05-10T11:58:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "2.9.1",
|
||||
|
4
resources/assets/js/components/TagsSelect.js
vendored
4
resources/assets/js/components/TagsSelect.js
vendored
@ -76,9 +76,7 @@ export default class TagsSelect {
|
||||
|
||||
this.$suggestionsContent.innerHTML = '';
|
||||
|
||||
tags.forEach(newTag => {
|
||||
newTag = newTag.trim();
|
||||
|
||||
tags.slice(0, 20).forEach(newTag => {
|
||||
const $tag = document.createElement('span');
|
||||
$tag.classList.add('btn', 'btn-outline-secondary', 'btn-xs');
|
||||
$tag.innerText = newTag;
|
||||
|
24
resources/assets/js/components/UrlField.js
vendored
24
resources/assets/js/components/UrlField.js
vendored
@ -76,7 +76,7 @@ export default class UrlField {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(window.appData.routes.fetch.htmlForUrl, {
|
||||
fetch(window.appData.routes.fetch.keywordsForUrl, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
@ -85,25 +85,11 @@ export default class UrlField {
|
||||
url: url
|
||||
})
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(body => {
|
||||
if (body !== null) {
|
||||
this.parseHtmlForKeywords(body);
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.keywords !== null) {
|
||||
this.tagSuggestions.displayNewSuggestions(data.keywords);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
parseHtmlForKeywords (body) {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(body, 'text/html');
|
||||
|
||||
if (doc.head.children.length > 0) {
|
||||
const keywords = doc.head.children.namedItem('keywords')
|
||||
|| doc.head.children.namedItem('Keywords');
|
||||
|
||||
if (keywords !== null && keywords.content.length > 0) {
|
||||
this.tagSuggestions.displayNewSuggestions(keywords.content.split(','));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
'searchLists' => route('fetch-lists'),
|
||||
'searchTags' => route('fetch-tags'),
|
||||
'existingLinks' => route('fetch-existing-links'),
|
||||
'htmlForUrl' => route('fetch-html-for-url'),
|
||||
'keywordsForUrl' => route('fetch-keywords-for-url'),
|
||||
'updateCheck' => route('fetch-update-check'),
|
||||
'generateApiToken' => route('generate-api-token'),
|
||||
'generateCronToken' => route('generate-cron-token'),
|
||||
|
@ -129,8 +129,8 @@ Route::group(['middleware' => ['auth']], function () {
|
||||
->name('fetch-lists');
|
||||
Route::post('fetch/existing-links', [FetchController::class, 'searchExistingUrls'])
|
||||
->name('fetch-existing-links');
|
||||
Route::post('fetch/html-for-url', [FetchController::class, 'htmlForUrl'])
|
||||
->name('fetch-html-for-url');
|
||||
Route::post('fetch/keywords-for-url', [FetchController::class, 'htmlKeywordsFromUrl'])
|
||||
->name('fetch-keywords-for-url');
|
||||
Route::get('fetch/update-check', [FetchController::class, 'checkForUpdates'])
|
||||
->name('fetch-update-check');
|
||||
|
||||
|
@ -82,46 +82,49 @@ class FetchControllerTest extends TestCase
|
||||
$response->assertOk()->assertJson(['linkFound' => false]);
|
||||
}
|
||||
|
||||
public function testGetHtmlForUrl(): void
|
||||
public function testGetHtmlKeywordsForUrl(): void
|
||||
{
|
||||
$testHtml = '<!DOCTYPE html><head>' .
|
||||
'<title>Example Title</title>' .
|
||||
'<meta name="description" content="This an example description">' .
|
||||
'<meta name="keywords" content="html, css, javascript">' .
|
||||
'</head></html>';
|
||||
|
||||
Http::fake([
|
||||
'example.com' => Http::response($testHtml, 200),
|
||||
]);
|
||||
|
||||
$response = $this->post('fetch/html-for-url', [
|
||||
$response = $this->post('fetch/keywords-for-url', [
|
||||
'url' => 'https://example.com',
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
|
||||
$responseHtml = $response->content();
|
||||
$this->assertEquals($testHtml, $responseHtml);
|
||||
$keywords = $response->json('keywords');
|
||||
$this->assertEquals('html', $keywords[0]);
|
||||
$this->assertEquals('css', $keywords[1]);
|
||||
$this->assertEquals('javascript', $keywords[2]);
|
||||
}
|
||||
|
||||
public function testGetHtmlForInvalidUrl(): void
|
||||
public function testGetKeywordsForInvalidUrl(): void
|
||||
{
|
||||
$response = $this->post('fetch/html-for-url', [
|
||||
$response = $this->post('fetch/keywords-for-url', [
|
||||
'url' => 'not a url',
|
||||
]);
|
||||
|
||||
$response->assertSessionHasErrors('url');
|
||||
}
|
||||
|
||||
public function testGetHtmlForUrlWithFailure(): void
|
||||
public function testGetKeywordsForUrlWithFailure(): void
|
||||
{
|
||||
Http::fake([
|
||||
'example.com' => Http::response('', 500),
|
||||
]);
|
||||
|
||||
$response = $this->post('fetch/html-for-url', [
|
||||
$response = $this->post('fetch/keywords-for-url', [
|
||||
'url' => 'https://example.com',
|
||||
]);
|
||||
|
||||
$response->assertOk()->assertSee('');
|
||||
$response->assertOk()->assertJson(['keywords' => null]);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user