feat(server): expose settings table API and compose get_settings from SA locks plus local edits

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-18 18:52:29 +03:30
co-authored by Cursor
parent 5337818396
commit 341b2da2c9
3 changed files with 66 additions and 37 deletions
@@ -28,10 +28,8 @@ class SettingsController extends Controller
->select(Setting::adminSelectColumns()) ->select(Setting::adminSelectColumns())
->orderBy('key'); ->orderBy('key');
$skipOverlay = $request->boolean('skip_overlay');
if ($request->boolean('system_only')) { if ($request->boolean('system_only')) {
if (! $skipOverlay) { if (! $request->boolean('skip_overlay')) {
$overlay = app(SuperAdminProgramSettingsOverlay::class)->items(); $overlay = app(SuperAdminProgramSettingsOverlay::class)->items();
if ($overlay) { if ($overlay) {
return response()->json($this->authorizeSettingsPayload($this->overlayToRows($overlay))); return response()->json($this->authorizeSettingsPayload($this->overlayToRows($overlay)));
@@ -40,7 +38,7 @@ class SettingsController extends Controller
$rows = $query $rows = $query
->where(function ($q) { ->where(function ($q) {
$q->where('can_edit', 0)->orWhere('can_edit', false); $q->where('can_edit', 0)->orWhere('can_edit', false)->orWhere('can_edit', '0');
}) })
->where(function ($q) { ->where(function ($q) {
$q->where('is_active', 1) $q->where('is_active', 1)
@@ -53,17 +51,30 @@ class SettingsController extends Controller
} }
if ($request->boolean('editable_only')) { if ($request->boolean('editable_only')) {
return response()->json($this->authorizeSettingsPayload($query->where('can_edit', 1)->get())); return response()->json($this->authorizeSettingsPayload(
$query->where(function ($q) {
$q->where('can_edit', 1)->orWhere('can_edit', true)->orWhere('can_edit', '1');
})->get()
));
} }
$local = $query->get(); $local = $query->get();
if ($skipOverlay) {
return response()->json($this->authorizeSettingsPayload($local));
}
return response()->json($this->authorizeSettingsPayload( return response()->json($this->authorizeSettingsPayload($this->composeGetSettings($local)));
$this->mergeOverlayIntoLocal($local) }
));
/**
* جدول settings همین نسخه — بدون overlay سوپرادمین.
* سوپرادمین برای ایمپورت از این مسیر can_edit=0 را برمی‌دارد.
*/
public function localTable()
{
$rows = Setting::query()
->select(Setting::adminSelectColumns())
->orderBy('key')
->get();
return response()->json($this->authorizeSettingsPayload($rows));
} }
public function edit(Request $request) public function edit(Request $request)
@@ -152,43 +163,55 @@ class SettingsController extends Controller
return in_array($key, self::PANEL_MANAGED_KEYS, true); return in_array($key, self::PANEL_MANAGED_KEYS, true);
} }
private function mergeOverlayIntoLocal($rows) /**
* get_settings: کلیدهای سوپرادمین (can_edit=0) + ردیف‌های جدول لوکال با can_edit=1.
* اگر سوپرادمین در دسترس نباشد کل جدول لوکال برمی‌گردد.
* کلیدهای runtime / متعلق به پنل خانگی همیشه از جدول لوکال می‌آیند.
*/
private function composeGetSettings($localRows)
{ {
$overlay = app(SuperAdminProgramSettingsOverlay::class)->items(); $overlay = app(SuperAdminProgramSettingsOverlay::class);
if (! $overlay) { $saMap = $overlay->map();
return $rows; if ($saMap === null) {
return $localRows;
} }
$byKey = []; $byKey = [];
foreach ($rows as $row) {
$byKey[(string) $row->key] = $row; foreach ($localRows as $row) {
if ($this->isEditableCanEdit($row->can_edit ?? null)) {
$byKey[(string) $row->key] = $row;
}
} }
foreach ($overlay as $item) { foreach ($saMap as $key => $item) {
$key = trim((string) ($item['key'] ?? '')); if (! is_array($item)) {
if ($key === '' || SuperAdminProgramSettingsOverlay::isLocalOwned($key)) {
continue; continue;
} }
if (isset($byKey[$key])) { $byKey[(string) $key] = $this->overlayRowToSetting($item);
$byKey[$key]->value = $item['value'] ?? $byKey[$key]->value; }
if (array_key_exists('title_fa', $item) && $item['title_fa'] !== null && $item['title_fa'] !== '') {
$byKey[$key]->title_fa = $item['title_fa']; foreach ($localRows as $row) {
} $key = (string) $row->key;
if (array_key_exists('description', $item) && $item['description'] !== null) { if (
$byKey[$key]->description = $item['description']; SuperAdminProgramSettingsOverlay::isLocalOwned($key)
} || SuperAdminProgramSettingsOverlay::isRuntime($key)
if (array_key_exists('type', $item) && $item['type'] !== null && $item['type'] !== '') { ) {
$byKey[$key]->type = $item['type']; $byKey[$key] = $row;
}
if (array_key_exists('is_active', $item)) {
$byKey[$key]->is_active = $item['is_active'];
}
} else {
$byKey[$key] = $this->overlayRowToSetting($item);
} }
} }
return collect(array_values($byKey)); return collect(array_values($byKey))->sortBy(fn ($row) => (string) ($row->key ?? ''))->values();
}
private function isEditableCanEdit(mixed $canEdit): bool
{
return $canEdit === 1 || $canEdit === true || $canEdit === '1';
}
private function mergeOverlayIntoLocal($rows)
{
return $this->composeGetSettings($rows);
} }
/** /**
@@ -100,6 +100,11 @@ class SuperAdminProgramSettingsOverlay
return $map[$key]; return $map[$key];
} }
public static function isRuntime(string $key): bool
{
return in_array($key, self::RUNTIME_KEYS, true);
}
public static function isLocalOwned(string $key): bool public static function isLocalOwned(string $key): bool
{ {
return in_array($key, self::LOCAL_OWNED_KEYS, true); return in_array($key, self::LOCAL_OWNED_KEYS, true);
+1
View File
@@ -39,6 +39,7 @@ Route::middleware('auth:user')->group(function (){
//settigs //settigs
Route::get('get_settings',[SettingsController::class, 'index']); Route::get('get_settings',[SettingsController::class, 'index']);
Route::post('get_settings',[SettingsController::class, 'edit']); Route::post('get_settings',[SettingsController::class, 'edit']);
Route::get('settings/table',[SettingsController::class, 'localTable']);
//------------balence //------------balence
Route::post('getBalance', [DashboardController::class, 'getBalance']); Route::post('getBalance', [DashboardController::class, 'getBalance']);