diff --git a/app/Api/V1/Controllers/System/ConfigurationController.php b/app/Api/V1/Controllers/System/ConfigurationController.php new file mode 100644 index 0000000000..f91cad2b8d --- /dev/null +++ b/app/Api/V1/Controllers/System/ConfigurationController.php @@ -0,0 +1,184 @@ +. + */ + +namespace FireflyIII\Api\V1\Controllers\System; + + +use FireflyIII\Api\V1\Controllers\Controller; +use FireflyIII\Api\V1\Requests\System\UpdateRequest; +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Repositories\User\UserRepositoryInterface; +use FireflyIII\Support\Binder\EitherConfigKey; +use Illuminate\Http\JsonResponse; +use Log; + +/** + * Class ConfigurationController + */ +class ConfigurationController extends Controller +{ + private UserRepositoryInterface $repository; + + /** + * ConfigurationController constructor. + */ + public function __construct() + { + parent::__construct(); + $this->middleware( + function ($request, $next) { + $this->repository = app(UserRepositoryInterface::class); + + return $next($request); + } + ); + } + + /** + * @return JsonResponse + * @throws FireflyException + */ + public function index(): JsonResponse + { + try { + $dynamicData = $this->getDynamicConfiguration(); + } catch (FireflyException $e) { + Log::error($e->getMessage()); + Log::error($e->getTraceAsString()); + throw new FireflyException('200030: Could not load config variables.'); + } + $staticData = $this->getStaticConfiguration(); + $return = []; + foreach ($dynamicData as $key => $value) { + $return[] = [ + 'title' => sprintf('configuration.%s', $key), + 'value' => $value, + 'editable' => true, + ]; + } + foreach ($staticData as $key => $value) { + $return[] = [ + 'title' => $key, + 'value' => $value, + 'editable' => false, + ]; + } + + return response()->json($return); + } + + /** + * @param string $configKey + * + * @return JsonResponse + * @throws FireflyException + */ + public function show(string $configKey): JsonResponse + { + $data = []; + $dynamic = $this->getDynamicConfiguration(); + $shortKey = str_replace('configuration.', '', $configKey); + if ('configuration.' === substr($configKey, 0, 14)) { + $data = [ + 'title' => $configKey, + 'value' => $dynamic[$shortKey], + 'editable' => true, + ]; + } + if ('configuration.' !== substr($configKey, 0, 14)) { + $data = [ + 'title' => $configKey, + 'value' => config($configKey), + 'editable' => false, + ]; + } + + return response()->json(['data' => $data])->header('Content-Type', self::CONTENT_TYPE); + } + + /** + * Update the configuration. + * + * @param UpdateRequest $request + * @param string $name + * + * @return JsonResponse + */ + public function update(UpdateRequest $request, string $name): JsonResponse + { + if (!$this->repository->hasRole(auth()->user(), 'owner')) { + throw new FireflyException('200005: You need the "owner" role to do this.'); // @codeCoverageIgnore + } + $data = $request->getAll(); + $shortName = str_replace('configuration.','', $name); + + app('fireflyconfig')->set($shortName, $data['value']); + + // get updated config: + $newConfig = $this->getDynamicConfiguration(); + + + $data = [ + 'title' => $name, + 'value' => $newConfig[$shortName], + 'editable' => true, + ]; + + return response()->json(['data' => $data])->header('Content-Type', self::CONTENT_TYPE); + } + + + /** + * @return array + */ + private function getStaticConfiguration(): array + { + $list = EitherConfigKey::$static; + $return = []; + foreach ($list as $key) { + $return[$key] = config($key); + } + + return $return; + } + + + /** + * Get all config values. + * + * @return array + * @throws FireflyException + */ + private function getDynamicConfiguration(): array + { + $isDemoSite = app('fireflyconfig')->get('is_demo_site'); + $updateCheck = app('fireflyconfig')->get('permission_update_check'); + $lastCheck = app('fireflyconfig')->get('last_update_check'); + $singleUser = app('fireflyconfig')->get('single_user_mode'); + + return [ + 'is_demo_site' => null === $isDemoSite ? null : $isDemoSite->data, + 'permission_update_check' => null === $updateCheck ? null : (int)$updateCheck->data, + 'last_update_check' => null === $lastCheck ? null : (int)$lastCheck->data, + 'single_user_mode' => null === $singleUser ? null : $singleUser->data, + ]; + } +} \ No newline at end of file diff --git a/app/Api/V1/Requests/todo/ConfigurationRequest.php b/app/Api/V1/Requests/System/UpdateRequest.php similarity index 75% rename from app/Api/V1/Requests/todo/ConfigurationRequest.php rename to app/Api/V1/Requests/System/UpdateRequest.php index 8de01f8985..cf6ddf5c6d 100644 --- a/app/Api/V1/Requests/todo/ConfigurationRequest.php +++ b/app/Api/V1/Requests/System/UpdateRequest.php @@ -22,7 +22,7 @@ declare(strict_types=1); -namespace FireflyIII\Api\V1\Requests; +namespace FireflyIII\Api\V1\Requests\System; use FireflyIII\Rules\IsBoolean; use FireflyIII\Support\Request\ChecksLogin; @@ -30,11 +30,11 @@ use FireflyIII\Support\Request\ConvertsDataTypes; use Illuminate\Foundation\Http\FormRequest; /** - * Class ConfigurationRequest + * Class UpdateRequest * * @codeCoverageIgnore */ -class ConfigurationRequest extends FormRequest +class UpdateRequest extends FormRequest { use ConvertsDataTypes, ChecksLogin; @@ -47,14 +47,15 @@ class ConfigurationRequest extends FormRequest */ public function getAll(): array { - $name = $this->route()->parameter('configName'); + $name = $this->route()->parameter('dynamicConfigKey'); switch ($name) { default: break; - case 'is_demo_site': - case 'single_user_mode': + case 'configuration.is_demo_site': + case 'configuration.single_user_mode': return ['value' => $this->boolean('value')]; - case 'permission_update_check': + case 'configuration.permission_update_check': + case 'configuration.last_update_check': return ['value' => $this->integer('value')]; } @@ -72,11 +73,13 @@ class ConfigurationRequest extends FormRequest switch ($name) { default: break; - case 'is_demo_site': - case 'single_user_mode': + case 'configuration.is_demo_site': + case 'configuration.single_user_mode': return ['value' => ['required', new IsBoolean]]; - case 'permission_update_check': + case 'configuration.permission_update_check': return ['value' => 'required|numeric|between:-1,1']; + case 'configuration.last_update_check': + return ['value' => 'required|numeric|min:464272080']; } return ['value' => 'required']; // @codeCoverageIgnore diff --git a/app/Support/Binder/DynamicConfigKey.php b/app/Support/Binder/DynamicConfigKey.php index 07b105eda1..d753f0c166 100644 --- a/app/Support/Binder/DynamicConfigKey.php +++ b/app/Support/Binder/DynamicConfigKey.php @@ -29,6 +29,13 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; */ class DynamicConfigKey { + + public static array $accepted = [ + 'configuration.is_demo_site', + 'configuration.permission_update_check', + 'configuration.single_user_mode', + 'configuration.last_update_check', + ]; /** * @param string $value * @param Route $route @@ -38,8 +45,7 @@ class DynamicConfigKey */ public static function routeBinder(string $value, Route $route): string { - $accepted = ['is_demo_site', 'permission_update_check', 'single_user_mode']; - if (in_array($value, $accepted, true)) { + if (in_array($value, self::$accepted, true)) { return $value; } throw new NotFoundHttpException; diff --git a/app/Support/Binder/StaticConfigKey.php b/app/Support/Binder/EitherConfigKey.php similarity index 86% rename from app/Support/Binder/StaticConfigKey.php rename to app/Support/Binder/EitherConfigKey.php index 0158eca4c3..33c1c9d715 100644 --- a/app/Support/Binder/StaticConfigKey.php +++ b/app/Support/Binder/EitherConfigKey.php @@ -26,16 +26,16 @@ use Illuminate\Routing\Route; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** - * Class StaticConfigKey + * Class EitherConfigKey */ -class StaticConfigKey +class EitherConfigKey { - public static array $accepted = [ + public static array $static = [ 'firefly.version', 'firefly.api_version', 'firefly.default_location', 'firefly.account_to_transaction', - 'firefly.allowed_opposing_types' + 'firefly.allowed_opposing_types', ]; /** * @param string $value @@ -46,7 +46,7 @@ class StaticConfigKey */ public static function routeBinder(string $value, Route $route): string { - if (in_array($value, self::$accepted, true)) { + if (in_array($value, self::$static, true) || in_array($value, DynamicConfigKey::$accepted, true)) { return $value; } throw new NotFoundHttpException; diff --git a/config/firefly.php b/config/firefly.php index 2cd144b5c7..156fc4f138 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -53,7 +53,7 @@ use FireflyIII\Support\Binder\CurrencyCode; use FireflyIII\Support\Binder\Date; use FireflyIII\Support\Binder\DynamicConfigKey; use FireflyIII\Support\Binder\JournalList; -use FireflyIII\Support\Binder\StaticConfigKey; +use FireflyIII\Support\Binder\EitherConfigKey; use FireflyIII\Support\Binder\TagList; use FireflyIII\Support\Binder\TagOrId; use FireflyIII\TransactionRules\Actions\AddTag; @@ -403,7 +403,7 @@ return [ 'cliToken' => CLIToken::class, 'tagOrId' => TagOrId::class, 'dynamicConfigKey' => DynamicConfigKey::class, - 'staticConfigKey' => StaticConfigKey::class, + 'eitherConfigKey' => EitherConfigKey::class, ], 'rule-actions' => [ diff --git a/routes/api.php b/routes/api.php index 7f6921ff65..d410d14cc9 100644 --- a/routes/api.php +++ b/routes/api.php @@ -488,7 +488,29 @@ Route::group( } ); +// Dynamic configuration API routes +Route::group( + ['namespace' => 'FireflyIII\Api\V1\Controllers\System', 'prefix' => 'configuration', + 'as' => 'api.v1.configuration.',], + static function () { + Route::get('', ['uses' => 'ConfigurationController@index', 'as' => 'index']); + Route::get('{eitherConfigKey}', ['uses' => 'ConfigurationController@show', 'as' => 'show']); + Route::put('{dynamicConfigKey}', ['uses' => 'ConfigurationController@update', 'as' => 'update']); + } +); +// STATIC CONFIGURATION (NOT CHANGEABLE) +// TODO VERIFY API DOCS +//Route::group( +// ['namespace' => 'FireflyIII\Api\V1\Controllers\System', 'prefix' => 'configuration/static', +// 'as' => 'api.v1.configuration.static.',], +// static function () { +// +// // Configuration API routes: +// Route::get('', ['uses' => 'StaticConfigController@index', 'as' => 'index']); +// Route::get('{staticConfigKey}', ['uses' => 'StaticConfigController@show', 'as' => 'show']); +// } +//); @@ -539,32 +561,7 @@ Route::group( -// DYNAMIC CONFIGURATION (CHANGEABLE) -//// TODO VERIFY API DOCS -//Route::group( -// ['namespace' => 'FireflyIII\Api\V1\Controllers\System', 'prefix' => 'configuration/dynamic', -// 'as' => 'api.v1.configuration.dynamic.',], -// static function () { -// -// // Configuration API routes: -// Route::get('', ['uses' => 'DynamicConfigController@index', 'as' => 'index']); -// Route::get('{dynamicConfigKey}', ['uses' => 'DynamicConfigController@show', 'as' => 'show']); -// Route::post('{dynamicConfigKey}', ['uses' => 'DynamicConfigController@update', 'as' => 'update']); -// } -//); -// STATIC CONFIGURATION (NOT CHANGEABLE) -// TODO VERIFY API DOCS -//Route::group( -// ['namespace' => 'FireflyIII\Api\V1\Controllers\System', 'prefix' => 'configuration/static', -// 'as' => 'api.v1.configuration.static.',], -// static function () { -// -// // Configuration API routes: -// Route::get('', ['uses' => 'StaticConfigController@index', 'as' => 'index']); -// Route::get('{staticConfigKey}', ['uses' => 'StaticConfigController@show', 'as' => 'show']); -// } -//);