From c321f0ec97fc237e282c3c89d8031298f0de395f Mon Sep 17 00:00:00 2001 From: dogukanoksuz Date: Wed, 16 Oct 2024 13:22:34 +0300 Subject: [PATCH 01/10] chore: Bump version to 2.1.1-dev --- storage/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/VERSION b/storage/VERSION index 879b416e..7c7e0966 100644 --- a/storage/VERSION +++ b/storage/VERSION @@ -1 +1 @@ -2.1 +2.1.1-dev From 2d9bbf844cb90a41962d560dba8cd2f721190e12 Mon Sep 17 00:00:00 2001 From: dogukanoksuz Date: Wed, 16 Oct 2024 13:24:07 +0300 Subject: [PATCH 02/10] feat: Remove unnecessary permission_data table --- app/Models/PermissionData.php | 17 -------------- ...0_16_132117_drop_permission_data_table.php | 23 +++++++++++++++++++ 2 files changed, 23 insertions(+), 17 deletions(-) delete mode 100644 app/Models/PermissionData.php create mode 100644 database/migrations/2024_10_16_132117_drop_permission_data_table.php diff --git a/app/Models/PermissionData.php b/app/Models/PermissionData.php deleted file mode 100644 index d13c3e65..00000000 --- a/app/Models/PermissionData.php +++ /dev/null @@ -1,17 +0,0 @@ - Date: Wed, 16 Oct 2024 13:59:33 +0300 Subject: [PATCH 03/10] feat: Drop all old tables that is not used --- .../2024_10_16_132807_drop_modules_table.php | 23 ++++++++++++++++++ ...0_16_132923_drop_monitor_servers_table.php | 23 ++++++++++++++++++ ...3118_drop_personal_access_tokens_table.php | 23 ++++++++++++++++++ ...4_10_16_133158_drop_replications_table.php | 24 +++++++++++++++++++ ..._10_16_133323_drop_user_monitors_table.php | 23 ++++++++++++++++++ 5 files changed, 116 insertions(+) create mode 100644 database/migrations/2024_10_16_132807_drop_modules_table.php create mode 100644 database/migrations/2024_10_16_132923_drop_monitor_servers_table.php create mode 100644 database/migrations/2024_10_16_133118_drop_personal_access_tokens_table.php create mode 100644 database/migrations/2024_10_16_133158_drop_replications_table.php create mode 100644 database/migrations/2024_10_16_133323_drop_user_monitors_table.php diff --git a/database/migrations/2024_10_16_132807_drop_modules_table.php b/database/migrations/2024_10_16_132807_drop_modules_table.php new file mode 100644 index 00000000..9ca4a710 --- /dev/null +++ b/database/migrations/2024_10_16_132807_drop_modules_table.php @@ -0,0 +1,23 @@ + Date: Wed, 16 Oct 2024 14:00:40 +0300 Subject: [PATCH 04/10] fix: ID fields was not marked as primary key --- ...25_alter_table_audit_logs_make_id_pkey.php | 26 +++++++++++++++++++ ...527_alter_table_auth_logs_make_id_pkey.php | 26 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 database/migrations/2024_10_16_133425_alter_table_audit_logs_make_id_pkey.php create mode 100644 database/migrations/2024_10_16_133527_alter_table_auth_logs_make_id_pkey.php diff --git a/database/migrations/2024_10_16_133425_alter_table_audit_logs_make_id_pkey.php b/database/migrations/2024_10_16_133425_alter_table_audit_logs_make_id_pkey.php new file mode 100644 index 00000000..b6993242 --- /dev/null +++ b/database/migrations/2024_10_16_133425_alter_table_audit_logs_make_id_pkey.php @@ -0,0 +1,26 @@ +primary('id')->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; diff --git a/database/migrations/2024_10_16_133527_alter_table_auth_logs_make_id_pkey.php b/database/migrations/2024_10_16_133527_alter_table_auth_logs_make_id_pkey.php new file mode 100644 index 00000000..7bf47059 --- /dev/null +++ b/database/migrations/2024_10_16_133527_alter_table_auth_logs_make_id_pkey.php @@ -0,0 +1,26 @@ +primary('id')->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; From c4646c86050e2515ce4a1abae848b18e8780676d Mon Sep 17 00:00:00 2001 From: dogukanoksuz Date: Thu, 17 Oct 2024 14:30:09 +0300 Subject: [PATCH 05/10] feat: Added type field on variables --- app/Http/Controllers/API/Settings/RoleController.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/API/Settings/RoleController.php b/app/Http/Controllers/API/Settings/RoleController.php index c39727ea..22fdb746 100644 --- a/app/Http/Controllers/API/Settings/RoleController.php +++ b/app/Http/Controllers/API/Settings/RoleController.php @@ -567,7 +567,7 @@ public function setVariables(Request $request) 'variable', $request->key, $request->value, - null, + $request->type ?? null, 'roles' ); @@ -581,6 +581,7 @@ public function setVariables(Request $request) 'role_id' => $request->role_id, 'key' => $request->key, 'value' => $request->value, + 'type' => $request->type ?? null, ] ], "ROLE_EDIT" @@ -598,7 +599,7 @@ public function deleteVariables(Request $request) { Permission::whereIn('id', $request->permission_ids)->delete(); - return response()->json('Fonksiyonlar başarıyla silindi.'); + return response()->json('Veri başarıyla silindi.'); } /** From 45afe7325251ed88bcd7595ad622c2be1fac2c25 Mon Sep 17 00:00:00 2001 From: dogukanoksuz Date: Thu, 17 Oct 2024 17:15:02 +0300 Subject: [PATCH 06/10] refactor: Simplify conditionals in ExtensionController and Helpers.php Simplified the conditionals in ExtensionController and Helpers.php to use boolean values instead of string comparisons. This improves readability and maintainability of the code. --- .../Controllers/API/ExtensionController.php | 8 +--- .../API/Settings/ExtensionController.php | 19 ++------- .../Controllers/HASync/MainController.php | 2 +- app/Http/Helpers.php | 2 +- app/Jobs/HighAvailabilitySyncer.php | 4 +- app/Models/Extension.php | 9 +--- app/Models/UserSettings.php | 2 + ...24_10_17_150509_alter_table_extensions.php | 42 +++++++++++++++++++ ...ersion_code_column_on_table_extensions.php | 32 ++++++++++++++ 9 files changed, 87 insertions(+), 33 deletions(-) create mode 100644 database/migrations/2024_10_17_150509_alter_table_extensions.php create mode 100644 database/migrations/2024_10_17_153851_fill_version_code_column_on_table_extensions.php diff --git a/app/Http/Controllers/API/ExtensionController.php b/app/Http/Controllers/API/ExtensionController.php index fb3791d5..bc2eaeb8 100644 --- a/app/Http/Controllers/API/ExtensionController.php +++ b/app/Http/Controllers/API/ExtensionController.php @@ -150,13 +150,7 @@ public function render(Request $request) $this->checkPermissions(extension()); $this->checkForMissingSettings($dbJson); - if (extension()->status == '0') { - return response()->json([ - 'message' => 'Eklenti şu anda güncelleniyor, biraz sonra tekrar deneyiniz.', - ], Response::HTTP_SERVICE_UNAVAILABLE); - } - - if (extension()->require_key == 'true' && server()->key() == null) { + if (extension()->require_key == true && server()->key() == null) { return response()->json([ 'message' => 'Bu eklentiyi kullanabilmek için bir anahtara ihtiyacınız var, lütfen kasa üzerinden bir anahtar ekleyin.', ], Response::HTTP_FORBIDDEN); diff --git a/app/Http/Controllers/API/Settings/ExtensionController.php b/app/Http/Controllers/API/Settings/ExtensionController.php index 589273bb..7d8f6cd6 100644 --- a/app/Http/Controllers/API/Settings/ExtensionController.php +++ b/app/Http/Controllers/API/Settings/ExtensionController.php @@ -102,10 +102,9 @@ public function upload() (string) request()->file('extension')->path() ); } - $list = $this->setupNewExtension($zipFile, $verify); - $error = $list[0]; - $new = $list[1]; - $old = $list[2] ?? []; + + list($error, $new, $old) = $this->setupNewExtension($zipFile); + $old = $old ?? []; if ($error) { return $error; @@ -284,7 +283,7 @@ public function download() * * @throws GuzzleException */ - private function setupNewExtension($zipFile, $verify = false) + private function setupNewExtension($zipFile) { // Initialize Zip Archive Object to use it later. $zip = new ZipArchive(); @@ -339,12 +338,6 @@ private function setupNewExtension($zipFile, $verify = false) ]; } - if ($verify) { - $json['issuer'] = explode(' ', (string) $verify, 4)[3]; - } else { - $json['issuer'] = ''; - } - // Check If Extension Already Exists. $extension = Extension::where('name', $json['name'])->first(); if ($extension) { @@ -369,12 +362,8 @@ private function setupNewExtension($zipFile, $verify = false) } else { $new = new Extension(); } - unset($json['issuer']); - unset($json['status']); - unset($json['order']); $json['display_name'] = json_encode($json['display_name']); $new->fill($json); - $new->status = '1'; $new->save(); if (array_key_exists('dependencies', $json) && $json['dependencies'] != '') { diff --git a/app/Http/Controllers/HASync/MainController.php b/app/Http/Controllers/HASync/MainController.php index 93cd5d82..161ed243 100644 --- a/app/Http/Controllers/HASync/MainController.php +++ b/app/Http/Controllers/HASync/MainController.php @@ -34,7 +34,7 @@ public function extensionList() $list[] = [ "id" => $extension->id, "name" => strtolower($extension->name), - "version_code" => (int) str_replace('.', '', $extension->version), + "version_code" => intval($extension->version_code), "download_path" => route("ha_download_ext", [ "extension_name" => $extension->name ]), diff --git a/app/Http/Helpers.php b/app/Http/Helpers.php index e667abd8..96ecc8f0 100755 --- a/app/Http/Helpers.php +++ b/app/Http/Helpers.php @@ -794,7 +794,7 @@ function callExtensionFunction( $params = [], $target_function = "apiProxy" ) { - if ($extension->require_key == 'true' && $server->key() == null) { + if ($extension->require_key == true && $server->key() == null) { return null; } diff --git a/app/Jobs/HighAvailabilitySyncer.php b/app/Jobs/HighAvailabilitySyncer.php index 6dfbf8f4..cd2fb722 100644 --- a/app/Jobs/HighAvailabilitySyncer.php +++ b/app/Jobs/HighAvailabilitySyncer.php @@ -144,9 +144,9 @@ private function fetchUpdateInformation($ip) if (is_file($path . '/db.json')) { $json = (array) json_decode(file_get_contents($path . '/db.json')); - $version = (int) str_replace('.', '', $json['version']); + $version = $json['version_code']; - if ($version < $extension->version_code) { + if (intval($version) < intval($extension->version_code)) { $needsToBeUpdated[] = $extension; continue; } diff --git a/app/Models/Extension.php b/app/Models/Extension.php index af50021d..2a902b69 100644 --- a/app/Models/Extension.php +++ b/app/Models/Extension.php @@ -24,21 +24,16 @@ class Extension extends Model 'display_name', 'name', 'version', + 'version_code', 'icon', - 'service', 'sslPorts', - 'issuer', - 'language', - 'support', - 'displays', 'require_key', - 'status', 'license_type', 'ldap_support', ]; protected $casts = [ - 'displays' => 'array', + 'require_key' => 'boolean', ]; /** diff --git a/app/Models/UserSettings.php b/app/Models/UserSettings.php index 33a9e087..a12dae8d 100644 --- a/app/Models/UserSettings.php +++ b/app/Models/UserSettings.php @@ -14,4 +14,6 @@ class UserSettings extends Model use UsesUuid; protected $fillable = ['server_id', 'user_id', 'name', 'value']; + + protected $hidden = ['value']; } diff --git a/database/migrations/2024_10_17_150509_alter_table_extensions.php b/database/migrations/2024_10_17_150509_alter_table_extensions.php new file mode 100644 index 00000000..737e80b1 --- /dev/null +++ b/database/migrations/2024_10_17_150509_alter_table_extensions.php @@ -0,0 +1,42 @@ +dropColumn('status'); + $table->dropColumn('displays'); + $table->dropColumn('support'); + $table->dropColumn('language'); + $table->dropColumn('issuer'); + $table->dropColumn('service'); + $table->dropColumn('order'); + // require_key defaults to false + // first convert existing data to boolean + DB::statement("ALTER TABLE extensions + ALTER COLUMN require_key DROP DEFAULT, + ALTER COLUMN require_key TYPE BOOLEAN USING require_key::BOOLEAN, + ALTER COLUMN require_key SET DEFAULT FALSE;"); + // add version_code column + $table->string('version_code')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; diff --git a/database/migrations/2024_10_17_153851_fill_version_code_column_on_table_extensions.php b/database/migrations/2024_10_17_153851_fill_version_code_column_on_table_extensions.php new file mode 100644 index 00000000..e0278f57 --- /dev/null +++ b/database/migrations/2024_10_17_153851_fill_version_code_column_on_table_extensions.php @@ -0,0 +1,32 @@ +name); + if (!$extJson) { + continue; + } + $extension->version_code = $extJson['version_code']; + $extension->save(); + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; From a2ec2967d275a46a0147bfc89b362e85e77fddca Mon Sep 17 00:00:00 2001 From: dogukanoksuz Date: Fri, 18 Oct 2024 16:11:04 +0300 Subject: [PATCH 07/10] refactor: Simplify conditionals in RoleController.php and add extension variables endpoint Simplified the conditionals in the `extensions` method of `RoleController.php` to improve readability and maintainability. Also added a new endpoint `getExtensionVariables` to retrieve extension variables from `db.json`. --- .../API/Settings/RoleController.php | 49 +++++++++++++++---- routes/api.php | 1 + 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/API/Settings/RoleController.php b/app/Http/Controllers/API/Settings/RoleController.php index 22fdb746..eb35bd76 100644 --- a/app/Http/Controllers/API/Settings/RoleController.php +++ b/app/Http/Controllers/API/Settings/RoleController.php @@ -234,13 +234,24 @@ public function setServers(Request $request) public function extensions(Request $request) { $extensions = Extension::all(); - $selected = Extension::find( - Role::find($request->role_id) - ->permissions - ->where('type', 'extension') - ->pluck('value') - ->toArray() - ); + $roles = Role::find($request->role_id) + ->permissions + ->where('type', 'extension') + ->pluck('value') + ->toArray(); + $selected = $extensions->filter(function ($extension) use ($roles) { + return in_array($extension->id, $roles); + })->values(); + + if ($request->variable_selector) { + $selected = [ + ...$selected, + [ + 'id' => 'default', + 'name' => 'Default KV', + ], + ]; + } return response()->json([ 'extensions' => $extensions, @@ -555,6 +566,17 @@ public function variables(Request $request) return response()->json($permissions); } + /** + * Get extension variables from db.json + */ + public function getExtensionVariables(Request $request) + { + $extension = Extension::find($request->extension_id); + $extJson = getExtensionJson($extension->name); + + return response()->json($extJson['variables'] ?? []); + } + /** * Add variable * @@ -562,12 +584,21 @@ public function variables(Request $request) */ public function setVariables(Request $request) { + switch ($request->type) { + case 'multiselect': + $value = json_encode($request->value); + break; + default: + $value = $request->value; + break; + } + Permission::grant( $request->role_id, 'variable', $request->key, - $request->value, - $request->type ?? null, + $value, + $request->type ?? 'string', 'roles' ); diff --git a/routes/api.php b/routes/api.php index 0d71e456..6b39f3e7 100644 --- a/routes/api.php +++ b/routes/api.php @@ -210,6 +210,7 @@ Route::post('/{extension_id}/license', [Settings\ExtensionController::class, 'license']); Route::get('/{extension_id}/download', [Settings\ExtensionController::class, 'download']); Route::get('/{extension_id}/functions', [Settings\RoleController::class, 'getExtensionFunctions']); + Route::get('/{extension_id}/variables', [Settings\RoleController::class, 'getExtensionVariables']); }); // Users From 48aa40695714d9b08ca104486c12b2a41c79bfe8 Mon Sep 17 00:00:00 2001 From: dogukanoksuz Date: Wed, 23 Oct 2024 12:39:04 +0000 Subject: [PATCH 08/10] feat: 2.1.1 Release --- storage/liman_system | Bin 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 storage/liman_system diff --git a/storage/liman_system b/storage/liman_system old mode 100644 new mode 100755 From a3e7855ab3f880f7284c09cfb6bcfb64131b24c6 Mon Sep 17 00:00:00 2001 From: dogukanoksuz Date: Wed, 23 Oct 2024 12:42:43 +0000 Subject: [PATCH 09/10] feat: 2.1.1 Release --- storage/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/VERSION b/storage/VERSION index 7c7e0966..7c327287 100644 --- a/storage/VERSION +++ b/storage/VERSION @@ -1 +1 @@ -2.1.1-dev +2.1.1 \ No newline at end of file From b1b2c1439c5c939ec89c56d697d728fd5c7c8ad4 Mon Sep 17 00:00:00 2001 From: dogukanoksuz Date: Wed, 23 Oct 2024 12:42:53 +0000 Subject: [PATCH 10/10] feat: New search system --- app/Http/Controllers/API/SearchController.php | 209 +++++++++++------- 1 file changed, 125 insertions(+), 84 deletions(-) diff --git a/app/Http/Controllers/API/SearchController.php b/app/Http/Controllers/API/SearchController.php index b189a425..4d08d097 100644 --- a/app/Http/Controllers/API/SearchController.php +++ b/app/Http/Controllers/API/SearchController.php @@ -7,6 +7,7 @@ use App\Models\Server; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Cache; /** * Search Controller @@ -24,114 +25,154 @@ class SearchController extends Controller public function search(Request $request) { $searchable = []; + $searchQuery = strtolower($request->input('query')); - // Get constant searchables - if (user()->isAdmin()) { - foreach (config('liman.search.admin') as $constant) { - if (isset($constant['children'])) { - foreach ($constant['children'] as $child) { - if (! isset($searchable[$constant['name']])) { - $searchable[$constant['name']] = []; - } - $child['name'] = __($child['name']); - $searchable[$constant['name']][] = $child; - } - } else { - if (! isset($searchable['Yönetim'])) { - $searchable['Yönetim'] = []; - } - $constant['name'] = __($constant['name']); - $searchable['Yönetim'][] = $constant; - } + $results = Cache::remember(auth('api')->user()->id . '_searchable_' . $searchQuery, now()->addHour(), function () use ($searchable, $searchQuery) { + $configs = [ + 'user' => 'Kullanıcı', + 'common' => 'Genel' + ]; + + if (auth('api')->user()->isAdmin()) { + $configs['admin'] = 'Yönetici'; } - } - foreach (config('liman.search.user') as $constant) { - if (isset($constant['children'])) { - foreach ($constant['children'] as $child) { - if (! isset($searchable[$constant['name']])) { - $searchable[$constant['name']] = []; - } - $child['name'] = __($child['name']); - $searchable[$constant['name']][] = $child; - } - } else { - if (! isset($searchable['Kullanıcı'])) { - $searchable['Kullanıcı'] = []; - } - $constant['name'] = __($constant['name']); - $searchable['Kullanıcı'][] = $constant; - } - } - - foreach (config('liman.search.common') as $constant) { - if (isset($constant['children'])) { - foreach ($constant['children'] as $child) { - if (! isset($searchable[$constant['name']])) { - $searchable[$constant['name']] = []; + foreach ($configs as $configKey => $defaultCategory) { + foreach (config("liman.search.$configKey") as $constant) { + $category = $constant['name'] ?? $defaultCategory; + if (isset($constant['children'])) { + foreach ($constant['children'] as $child) { + $child['name'] = __($child['name']); + $searchable[$category][] = $child; + } + } else { + $constant['name'] = __($constant['name']); + $searchable[$defaultCategory][] = $constant; } - $child['name'] = __($child['name']); - $searchable[$constant['name']][] = $child; - } - } else { - if (! isset($searchable['Genel'])) { - $searchable['Genel'] = []; } - $constant['name'] = __($constant['name']); - $searchable['Genel'][] = $constant; } - } - // Server searching - $servers = Server::select('id', 'name')->get() - ->filter(function ($server) { - return Permission::can(user()->id, 'server', 'id', $server->id); - }); + $servers = Server::select('id', 'name') + ->get() + ->filter(function ($server) { + return Permission::can(user()->id, 'server', 'id', $server->id); + }); - $searchable['Sunucular'] = []; - foreach ($servers as $server) { - if (Permission::can(user()->id, 'liman', 'id', 'server_details')) { + foreach ($servers as $server) { $searchable['Sunucular'][] = [ 'name' => $server->name, 'url' => "/servers/$server->id", ]; - } - $extensions = $server->extensions(); - foreach ($extensions as $extension) { - if (! isset($searchable[$server->name])) { - $searchable[$server->name] = []; - } - - if (! empty($extension->display_name)) { + foreach ($server->extensions() as $extension) { $searchable[$server->name][] = [ - 'name' => $extension->display_name, + 'name' => $extension->display_name ?: $extension->name, 'url' => "/servers/$server->id/extensions/$extension->id", ]; - continue; + $searchSettings = getExtensionJson($extension->name)["search"] ?? []; + foreach ($searchSettings as $search) { + $searchable[$server->name] = [ + ...$searchable[$server->name], + ...$this->searchFromExtensions($server, $extension, $search, $searchQuery) + ]; + } } - $searchable[$server->name][] = [ - 'name' => $extension->name, - 'url' => "/servers/$server->id/extensions/$extension->id", - ]; } - } - - $results = []; - $searchQuery = $request->input('query'); - foreach ($searchable as $category => $items) { - foreach ($items as $item) { - if (str_contains(strtolower($item['name']), strtolower($searchQuery))) { - if (! isset($results[$category])) { - $results[$category] = []; + $results = []; + foreach ($searchable as $category => $items) { + foreach ($items as $item) { + if (str_contains(strtolower($item['name']), $searchQuery)) { + $results[$category][] = $item; } - $results[$category][] = $item; } } + + return json_encode($results); + }); + + return $results; + } + + /** + * Search from microservices + */ + private function searchFromExtensions($server, $extension, $settings, $searchQuery) { + // Check if permission exists + if (! Permission::can(auth('api')->user()->id, 'function', 'name', $extension->name, $settings['permission'])) + return []; + + if (strlen($searchQuery) < 2) + return []; + + if (is_array($settings['search']['query_parameters'])) + $settings['search']['query_parameters'] = json_encode($settings['search']['query_parameters']); + + $settings['search']['query_parameters'] = str_replace( + sprintf("%%%%%s%%%%", $settings['search']['key']), + $searchQuery, + $settings['search']['query_parameters'] + ); + + $settings['request'][$settings['search']['append_to']] .= + sprintf("?%s=%s", $settings['search']['query_key'], $settings['search']['query_parameters']); + + $extensionCall = Cache::remember( + sprintf( + "%s_search_%s_%s_%s_%s", + auth('api')->user()->id, + $server->id, + $extension->id, + $searchQuery, + json_encode($settings['request']) + ), + $settings['metadata']['cache_enabled'] ? now()->addHours(2) : now()->addSeconds(15), + function () use ($server, $extension, $settings) { + return callExtensionFunction( + $extension, + $server, + $settings['request'], + $settings['function'], + ($settings['metadata']['timeout_ms'] / 1000) ?: 5 + ); + }, + ); + + $records = []; + if (is_array($extensionCall)) { + $records = empty($settings['result']['take_from']) ? $extensionCall : ($extensionCall[$settings['result']['take_from']] ?? []); + } elseif (is_object($extensionCall)) { + $records = empty($settings['result']['take_from']) ? (array) $extensionCall : ((array) $extensionCall->{$settings['result']['take_from']} ?? []); + } + + $results = []; + preg_match_all("/%%(.*?)%%/", $settings['result']['format'], $resultKeys); + preg_match_all("/%%(.*?)%%/", $settings['metadata']['url_format'], $urlKeys); + foreach ($records as $record) { + $record = (array) $record; + $results[] = [ + 'name' => (function () use ($resultKeys, $record, $settings) { + $name = $settings['result']['format']; + foreach ($resultKeys[1] as $key) { + $name = str_replace("%%$key%%", $record[$key] ?? '', $name); + } + return $name; + })(), + 'url' => (function () use ($urlKeys, $record, $settings, $server, $extension) { + $url = $settings['metadata']['url_format']; + foreach ($urlKeys[1] as $key) { + $url = str_replace("%%$key%%", $record[$key] ?? '', $url); + } + return sprintf( + "/servers/%s/extensions/%s", + $server->id, + $extension->id + ) . $url; + })(), + ]; } - return response()->json((object) $results); + return $results; } }