Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actions/run-tests/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ runs:
--run-integration-tests
--run-migration-tests
--extract-code-coverage
--keep-code-coverage
--install-composer-deps;
echo "test_result=$?" >> $GITHUB_ENV

Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
[#1204](https://github.com/nextcloud/cookbook/pull/1204) @christianlupus
- Update stylelint-config-idiomatic and fix code styling
[#1224](https://github.com/nextcloud/cookbook/pull/1224) @christianlupus
- Remove obsolete code from Recipe service class
[#1226](https://github.com/nextcloud/cookbook/pull/1226) @christianlupus

### Removed
- Remove the deprecated endpoints from version 0.9.15
Expand Down
264 changes: 0 additions & 264 deletions lib/Service/RecipeService.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
use OCA\Cookbook\Exception\HtmlParsingException;
use OCA\Cookbook\Exception\ImportException;
use OCA\Cookbook\Helper\Filter\JSONFilter;
use OCA\Cookbook\Helper\TextCleanupHelper;

/**
* Main service class for the cookbook app.
Expand Down Expand Up @@ -54,8 +53,6 @@ class RecipeService {
*/
private $userConfigHelper;

/** @var TextCleanupHelper */
private $textCleanupHelper;
/**
* @var ImageService
*/
Expand All @@ -75,7 +72,6 @@ public function __construct(
LoggerInterface $logger,
HtmlDownloadService $downloadService,
RecipeExtractionService $extractionService,
TextCleanupHelper $textCleanupHelper,
JSONFilter $jsonFilter
) {
$this->user_id = $UserId;
Expand All @@ -88,7 +84,6 @@ public function __construct(
$this->imageService = $imageService;
$this->htmlDownloadService = $downloadService;
$this->recipeExtractionService = $extractionService;
$this->textCleanupHelper = $textCleanupHelper;
$this->jsonFilter = $jsonFilter;
}

Expand Down Expand Up @@ -177,234 +172,6 @@ public function checkRecipe(array $json): array {
return $this->jsonFilter->apply($json);
}

/**
* @param string $html
* @param mixed $url
*
* @return array
* @deprecated
*/
private function parseRecipeHtml($url, $html) {
if (!$html) {
return null;
}

// Make sure we don't have any encoded entities in the HTML string
$html = html_entity_decode($html);

// Start document parser
$document = new \DOMDocument();

$libxml_previous_state = libxml_use_internal_errors(true);

try {
if (!$document->loadHTML($html)) {
throw new \Exception('Malformed HTML');
}
$errors = libxml_get_errors();
$this->display_libxml_errors($url, $errors);
libxml_clear_errors();
} finally {
libxml_use_internal_errors($libxml_previous_state);
}

$xpath = new \DOMXPath($document);

$json_ld_elements = $xpath->query("//*[@type='application/ld+json']");

foreach ($json_ld_elements as $json_ld_element) {
if (!$json_ld_element || !$json_ld_element->nodeValue) {
continue;
}

$string = $json_ld_element->nodeValue;

// Some recipes have newlines inside quotes, which is invalid JSON. Fix this before continuing.
$string = preg_replace('/\s+/', ' ', $string);

$json = json_decode($string, true);

// Look through @graph field for recipe
if ($json && isset($json['@graph']) && is_array($json['@graph'])) {
foreach ($json['@graph'] as $graph_item) {
if (!isset($graph_item['@type']) || $graph_item['@type'] !== 'Recipe') {
continue;
}

$json = $graph_item;
break;
}
}

// Check if json is an array for some reason
if ($json && isset($json[0])) {
foreach ($json as $element) {
if (!$element || !isset($element['@type']) || $element['@type'] !== 'Recipe') {
continue;
}
return $this->checkRecipe($element);
}
}

if (!$json || !isset($json['@type']) || $json['@type'] !== 'Recipe') {
continue;
}

return $this->checkRecipe($json);
}

// Parse HTML if JSON couldn't be found
$json = [];

$recipes = $xpath->query("//*[@itemtype='http://schema.org/Recipe']");

if (!isset($recipes[0])) {
throw new \Exception('Could not find recipe element');
}

$props = [
'name',
'image', 'images', 'thumbnail',
'recipeYield',
'keywords',
'recipeIngredient', 'ingredients',
'recipeInstructions', 'instructions', 'steps', 'guide',
];

foreach ($props as $prop) {
$prop_elements = $xpath->query("//*[@itemprop='" . $prop . "']");

foreach ($prop_elements as $prop_element) {
switch ($prop) {
case 'image':
case 'images':
case 'thumbnail':
$prop = 'image';

if (!isset($json[$prop]) || !is_array($json[$prop])) {
$json[$prop] = [];
}

if (!empty($prop_element->getAttribute('src'))) {
array_push($json[$prop], $prop_element->getAttribute('src'));
} elseif (
null !== $prop_element->getAttributeNode('content') &&
!empty($prop_element->getAttributeNode('content')->value)
) {
array_push($json[$prop], $prop_element->getAttributeNode('content')->value);
}

break;

case 'recipeIngredient':
case 'ingredients':
$prop = 'recipeIngredient';

if (!isset($json[$prop]) || !is_array($json[$prop])) {
$json[$prop] = [];
}

if (
null !== $prop_element->getAttributeNode('content') &&
!empty($prop_element->getAttributeNode('content')->value)
) {
array_push($json[$prop], $prop_element->getAttributeNode('content')->value);
} else {
array_push($json[$prop], $prop_element->nodeValue);
}

break;

case 'recipeInstructions':
case 'instructions':
case 'steps':
case 'guide':
$prop = 'recipeInstructions';

if (!isset($json[$prop]) || !is_array($json[$prop])) {
$json[$prop] = [];
}

if (
null !== $prop_element->getAttributeNode('content') &&
!empty($prop_element->getAttributeNode('content')->value)
) {
array_push($json[$prop], $prop_element->getAttributeNode('content')->value);
} else {
array_push($json[$prop], $prop_element->nodeValue);
}
break;

default:
if (isset($json[$prop]) && $json[$prop]) {
break;
}

if (
null !== $prop_element->getAttributeNode('content') &&
!empty($prop_element->getAttributeNode('content')->value)
) {
$json[$prop] = $prop_element->getAttributeNode('content')->value;
} else {
$json[$prop] = $prop_element->nodeValue;
}
break;
}
}
}

// Make one final desparate attempt at getting the instructions
if (!isset($json['recipeInstructions']) || !$json['recipeInstructions'] || sizeof($json['recipeInstructions']) < 1) {
$json['recipeInstructions'] = [];

$step_elements = $recipes[0]->getElementsByTagName('p');

foreach ($step_elements as $step_element) {
if (!$step_element || !$step_element->nodeValue) {
continue;
}

array_push($json['recipeInstructions'], $step_element->nodeValue);
}
}

return $this->checkRecipe($json);
}

private function display_libxml_errors($url, $errors) {
$error_counter = [];
$by_error_code = [];

foreach ($errors as $error) {
$count = array_key_exists($error->code, $error_counter) ? $error_counter[$error->code] : 0;
$error_counter[$error->code] = $count + 1;
$by_error_code[$error->code] = $error;
}

foreach ($error_counter as $code => $count) {
$error = $by_error_code[$code];

switch ($error->level) {
case LIBXML_ERR_WARNING:
$error_message = "libxml: Warning $error->code ";
break;
case LIBXML_ERR_ERROR:
$error_message = "libxml: Error $error->code ";
break;
case LIBXML_ERR_FATAL:
$error_message = "libxml: Fatal Error $error->code ";
break;
default:
$error_message = "Unknown Error ";
}

$error_message .= "occurred " . $count . " times while parsing " . $url . ". Last time in line $error->line" .
" and column $error->column: " . $error->message;

$this->logger->warning($error_message);
}
}

/**
* @param int $id
*/
Expand Down Expand Up @@ -791,26 +558,6 @@ public function getRecipeImageFileByFolderId($id, $size = 'thumb'): File {
}
}

/**
* Test if file is an image
*
* @param File $file
*
* @return bool
*/
private function isImage($file) {
$allowedExtensions = ['jpg', 'jpeg', 'png'];
if ($file->getType() !== 'file') {
return false;
}
$ext = pathinfo($file->getName(), PATHINFO_EXTENSION);
$iext = strtolower($ext);
if (!in_array($iext, $allowedExtensions)) {
return false;
}
return true;
}

/**
* Test if file is a recipe
*
Expand All @@ -834,15 +581,4 @@ private function isRecipeFile($file) {

return true;
}

/**
* @param string $str
* @param mixed $preserve_newlines
* @param mixed $remove_slashes
*
* @return string
*/
private function cleanUpString($str, $preserve_newlines = false, $remove_slashes = false) {
return $this->textCleanupHelper->cleanUp($str, !$preserve_newlines, $remove_slashes);
}
}