Skip to content
Open
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
3 changes: 3 additions & 0 deletions .changelog/current/2825-add-browserless-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Added

- Added support for browserless
14 changes: 14 additions & 0 deletions docs/dev/api/0.1.2/objects.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ VisibleInfoBlocks:
example: false
description: Show the list of tools in the UI

BrowserlessConfig:
type: object
properties:
url:
type: string
example: http://localhost:3000
nullable: true
token:
type: string
example: ABCD
nullable: true

Config:
type: object
description: An object describing the configuration of the web app
Expand All @@ -66,6 +78,8 @@ Config:
description: True, if the user wished to print the recipe images with the rest of the recipes
visibleInfoBlocks:
$ref: "#/VisibleInfoBlocks"
browserless_config:
$reg: "#/BrowserlessConfig"

Error:
type: object
Expand Down
Binary file added docs/user/assets/settings-browserless.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions docs/user/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,17 @@ Currently, the only way to share recipes is by sharing the Nextcloud folder that
### Public Sharing

At the moment it is not possible to share a public link to a recipe.

## Browserless configuration

By default cookbook fetches recipe pages via code. Some websites detect this (bot detection) and will block this request from accessing the website resulting in being unable to import the recipe.
To prevent this you can configure browserless. Browserless is a service that allows downloading a webpage more user-like and thus bypasses a lot of bot-detections on websites.

To set this up you should supply an URL and a token.

<img src="assets/settings-browserless.png" alt="Cookbook settings - Browserless" width="200px" />

You can create an account at https://www.browserless.io/ or setup a self-hosted instance.

For the url be sure to supply the REST API url, see https://docs.browserless.io/overview/connection-urls.
For the Amsterdam region this would be: https://production-ams.browserless.io
6 changes: 6 additions & 0 deletions lib/Controller/Implementation/ConfigImplementation.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public function __construct(
}

protected const KEY_VISIBLE_INFO_BLOCKS = 'visibleInfoBlocks';
protected const KEY_BROWSERLESS_CONFIG = 'browserless_config';

/**
* Get the current configuration of the app
Expand All @@ -46,6 +47,7 @@ public function list() {
'update_interval' => $this->dbCacheService->getSearchIndexUpdateInterval(),
'print_image' => $this->service->getPrintImage(),
self::KEY_VISIBLE_INFO_BLOCKS => $this->service->getVisibleInfoBlocks(),
self::KEY_BROWSERLESS_CONFIG => $this->service->getBrowserlessConfig(),
], Http::STATUS_OK);
}

Expand Down Expand Up @@ -79,6 +81,10 @@ public function config() {
$this->service->setVisibleInfoBlocks($data[self::KEY_VISIBLE_INFO_BLOCKS]);
}

if (isset($data[self::KEY_BROWSERLESS_CONFIG])) {
$this->service->setBrowserlessConfig($data[self::KEY_BROWSERLESS_CONFIG]);
}

$this->dbCacheService->triggerCheck();

return new JSONResponse('OK', Http::STATUS_OK);
Expand Down
125 changes: 57 additions & 68 deletions lib/Helper/UserConfigHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

namespace OCA\Cookbook\Helper;

use NCU\Config\IUserConfig;
use OCA\Cookbook\AppInfo\Application;
use OCA\Cookbook\Exception\UserNotLoggedInException;
use OCP\IConfig;
use OCP\IL10N;

/**
Expand All @@ -17,7 +17,7 @@ class UserConfigHelper {
private $userId;

/**
* @var IConfig
* @var IUserConfig
*/
private $config;

Expand All @@ -28,7 +28,7 @@ class UserConfigHelper {

public function __construct(
?string $UserId,
IConfig $config,
IUserConfig $config,
IL10N $l,
) {
$this->userId = $UserId;
Expand All @@ -41,6 +41,7 @@ public function __construct(
protected const KEY_PRINT_IMAGE = 'print_image';
protected const KEY_VISIBLE_INFO_BLOCKS = 'visible_info_blocks';
protected const KEY_FOLDER = 'folder';
protected const KEY_BROWSERLESS_CONFIG = 'browserless_config';

/**
* Checks if the user is logged in and the configuration can be obtained at all
Expand All @@ -53,43 +54,15 @@ private function ensureUserIsLoggedIn(): void {
}
}

/**
* Get a config value from the database
*
* @param string $key The key to get
* @return string The resulting value or '' if the key was not found
* @throws UserNotLoggedInException if no user is logged in
*/
private function getRawValue(string $key): string {
$this->ensureUserIsLoggedIn();
return $this->config->getUserValue($this->userId, Application::APP_ID, $key);
}

/**
* Set a config value in the database
*
* @param string $key The key of the configuration
* @param string $value The value of the config entry
* @throws UserNotLoggedInException if no user is logged in
*/
private function setRawValue(string $key, string $value): void {
$this->ensureUserIsLoggedIn();
$this->config->setUserValue($this->userId, Application::APP_ID, $key, $value);
}

/**
* Get the timestamp of the last rescan of the library
*
* @return int The timestamp of the last index rebuild
* @throws UserNotLoggedInException if no user is logged in
*/
public function getLastIndexUpdate(): int {
$rawValue = $this->getRawValue(self::KEY_LAST_INDEX_UPDATE);
if ($rawValue === '') {
return 0;
}

return intval($rawValue);
$this->ensureUserIsLoggedIn();
return $this->config->getValueInt($this->userId, Application::APP_ID, self::KEY_LAST_INDEX_UPDATE, 0);
}

/**
Expand All @@ -99,7 +72,8 @@ public function getLastIndexUpdate(): int {
* @throws UserNotLoggedInException if no user is logged in
*/
public function setLastIndexUpdate(int $value): void {
$this->setRawValue(self::KEY_LAST_INDEX_UPDATE, strval($value));
$this->ensureUserIsLoggedIn();
$this->config->setValueInt($this->userId, Application::APP_ID, self::KEY_LAST_INDEX_UPDATE, $value);
}

/**
Expand All @@ -109,12 +83,8 @@ public function setLastIndexUpdate(int $value): void {
* @throws UserNotLoggedInException if no user is logged in
*/
public function getUpdateInterval(): int {
$rawValue = $this->getRawValue(self::KEY_UPDATE_INTERVAL);
if ($rawValue === '') {
return 5;
}

return intval($rawValue);
$this->ensureUserIsLoggedIn();
return $this->config->getValueInt($this->userId, Application::APP_ID, self::KEY_UPDATE_INTERVAL, 5);
}

/**
Expand All @@ -124,7 +94,8 @@ public function getUpdateInterval(): int {
* @throws UserNotLoggedInException if no user is logged in
*/
public function setUpdateInterval(int $value): void {
$this->setRawValue(self::KEY_UPDATE_INTERVAL, (string)$value);
$this->ensureUserIsLoggedIn();
$this->config->setValueInt($this->userId, Application::APP_ID, self::KEY_UPDATE_INTERVAL, $value);
}

/**
Expand All @@ -134,12 +105,8 @@ public function setUpdateInterval(int $value): void {
* @throws UserNotLoggedInException if no user is logged in
*/
public function getPrintImage(): bool {
$rawValue = $this->getRawValue(self::KEY_PRINT_IMAGE);
if ($rawValue === '') {
return true;
}

return $rawValue === '1';
$this->ensureUserIsLoggedIn();
return $this->config->getValueBool($this->userId, Application::APP_ID, self::KEY_PRINT_IMAGE, true);
}

/**
Expand All @@ -149,11 +116,8 @@ public function getPrintImage(): bool {
* @throws UserNotLoggedInException if no user is logged in
*/
public function setPrintImage(bool $value): void {
if ($value) {
$this->setRawValue(self::KEY_PRINT_IMAGE, '1');
} else {
$this->setRawValue(self::KEY_PRINT_IMAGE, '0');
}
$this->ensureUserIsLoggedIn();
$this->config->setValueBool($this->userId, Application::APP_ID, self::KEY_PRINT_IMAGE, $value);
}

/**
Expand All @@ -163,19 +127,15 @@ public function setPrintImage(bool $value): void {
* @throws UserNotLoggedInException if no user is logged in
*/
public function getVisibleInfoBlocks(): array {
$rawValue = $this->getRawValue(self::KEY_VISIBLE_INFO_BLOCKS);

if ($rawValue === '') {
return [
'preparation-time' => true,
'cooking-time' => true,
'total-time' => true,
'nutrition-information' => true,
'tools' => true,
];
}

return json_decode($rawValue, true);
$this->ensureUserIsLoggedIn();
$default = [
'preparation-time' => true,
'cooking-time' => true,
'total-time' => true,
'nutrition-information' => true,
'tools' => true,
];
return $this->config->getValueArray($this->userId, Application::APP_ID, self::KEY_VISIBLE_INFO_BLOCKS, $default);
}

/**
Expand All @@ -185,7 +145,8 @@ public function getVisibleInfoBlocks(): array {
* @throws UserNotLoggedInException if no user is logged in
*/
public function setVisibleInfoBlocks(array $visibleInfoBlocks): void {
$this->setRawValue(self::KEY_VISIBLE_INFO_BLOCKS, json_encode($visibleInfoBlocks));
$this->ensureUserIsLoggedIn();
$this->config->setValueArray($this->userId, Application::APP_ID, self::KEY_VISIBLE_INFO_BLOCKS, $visibleInfoBlocks);
}

/**
Expand All @@ -201,7 +162,8 @@ public function setVisibleInfoBlocks(array $visibleInfoBlocks): void {
* @throws UserNotLoggedInException if no user is logged in
*/
public function getFolderName(): string {
$rawValue = $this->getRawValue(self::KEY_FOLDER);
$this->ensureUserIsLoggedIn();
$rawValue = $this->config->getValueString($this->userId, Application::APP_ID, self::KEY_FOLDER, '');

if ($rawValue === '') {
$path = '/' . $this->l->t('Recipes');
Expand All @@ -224,6 +186,33 @@ public function getFolderName(): string {
* @throws UserNotLoggedInException if no user is logged in
*/
public function setFolderName(string $value): void {
$this->setRawValue(self::KEY_FOLDER, $value);
$this->ensureUserIsLoggedIn();
$this->config->setValueString($this->userId, Application::APP_ID, self::KEY_FOLDER, $value);
}

/**
* Gets the browserless config from the configuration
*
* @return array<string, string | null> keys: url and token, values: url and token
* @throws UserNotLoggedInException if no user is logged in
*/
public function getBrowserlessConfig(): array {
$this->ensureUserIsLoggedIn();
$default = [
'url' => null,
'token' => null,
];
return $this->config->getValueArray($this->userId, Application::APP_ID, self::KEY_BROWSERLESS_CONFIG, $default);
}

/**
* Sets the browserless config in the configuration
*
* @param array<string, bool> keys: url and token, values: url and token
* @throws UserNotLoggedInException if no user is logged in
*/
public function setBrowserlessConfig(array $data): void {
$this->ensureUserIsLoggedIn();
$this->config->setValueArray($this->userId, Application::APP_ID, self::KEY_BROWSERLESS_CONFIG, $data, flags: IUserConfig::FLAG_SENSITIVE);
}
}
Loading