앞선 커밋이 CHANGELOG 에 주장한 "로딩 표시가 나오지 않던 문제 수정" 이 실제로 화면에 나타나는지 브라우저로 확정했다. 전달 경로부터 DOM 마운트·해제까지 측정했고, 지연·에러 응답에서도 영구 로딩이 남지 않음을 확인했다. 측정 과정에서 앞선 세션의 판단 하나가 틀렸음을 확인했다 — "오버레이 DOM 이 어느 화면에서도 관측되지 않는다" 는 관측 대상 노드를 잘못 잡은 것이었다. 스피너 방식 레이아웃은 다른 노드를 쓰며, 대조군에서도 안 보였던 이유가 이것이다. 미뤄 두었던 과제 4건을 함께 구현했다. - 인증창을 그냥 닫고 이탈하면 그 인증 요청을 서버에도 종료로 표시한다. 이전에는 브라우저만 알고 있어 인증 이력에 "보낸 뒤 소식 없는" 항목이 남았다 - 플러그인 설정 화면이 저장된 비밀값을 다시 내려받던 것을 가려서 표시한다. 그 항목을 건드리지 않고 저장하면 저장된 값이 그대로 유지된다 - 언어팩 반영 누락 검사가 버전만 비교해 "버전 같고 내용 다름" 을 놓치던 사각을 콘텐츠 비교로 닫았다 - 확장이 검증 규칙을 추가할 때 쓰는 필터 이름 6개를 표준 형태로 통일했다. 예전 이름도 함께 발행하므로 기존 확장은 수정 없이 동작한다 정적 검사 룰 2종의 오탐·사각을 함께 고쳤고, 개명으로 검사 대상에 편입된 파일의 사전 결함 8건을 해소했다. 검수용 데이터는 전량 정리했다.
115 lines
4.1 KiB
PHP
115 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\Admin;
|
|
|
|
use App\Extension\PluginManager;
|
|
use App\Http\Controllers\Api\Base\AdminBaseController;
|
|
use App\Http\Requests\Admin\UpdatePluginSettingsRequest;
|
|
use App\Services\PluginSettingsService;
|
|
use App\Support\SensitiveSettingMask;
|
|
use Illuminate\Http\JsonResponse;
|
|
|
|
/**
|
|
* 플러그인 설정 API 컨트롤러
|
|
*
|
|
* 플러그인의 설정 조회, 수정, 레이아웃 조회 기능을 제공합니다.
|
|
*/
|
|
class PluginSettingsController extends AdminBaseController
|
|
{
|
|
/**
|
|
* PluginSettingsController 생성자
|
|
*
|
|
* @param PluginSettingsService $pluginSettingsService 플러그인 설정 서비스
|
|
* @param PluginManager $pluginManager 설정 스키마(sensitive 플래그) 조회용
|
|
*/
|
|
public function __construct(
|
|
private PluginSettingsService $pluginSettingsService,
|
|
private PluginManager $pluginManager
|
|
) {
|
|
parent::__construct();
|
|
}
|
|
|
|
/**
|
|
* 응답에 실을 설정에서 민감값을 마스크로 치환한다.
|
|
*
|
|
* 이 응답은 관리자 화면으로 나가므로 암호화 키·시크릿의 평문이 브라우저·개발자 도구·프록시
|
|
* 로그에 남지 않아야 한다. 값이 저장되어 있다는 사실만 마스크로 알린다. 운영자가 값을 건드리지
|
|
* 않으면 화면이 마스크를 그대로 되돌려 보내고, 저장 단계가 그것을 걸러 기존 값을 보존한다.
|
|
*
|
|
* @param string $identifier 플러그인 식별자
|
|
* @param array<string, mixed> $settings 복호화된 설정
|
|
* @return array<string, mixed> 마스킹된 설정
|
|
*/
|
|
private function maskSensitive(string $identifier, array $settings): array
|
|
{
|
|
$plugin = $this->pluginManager->getPlugin($identifier);
|
|
|
|
return $plugin === null
|
|
? $settings
|
|
: SensitiveSettingMask::apply($settings, $plugin->getSettingsSchema());
|
|
}
|
|
|
|
/**
|
|
* 플러그인 설정을 조회합니다.
|
|
*
|
|
* @param string $identifier 플러그인 식별자
|
|
* @return JsonResponse 설정 데이터
|
|
*/
|
|
public function show(string $identifier): JsonResponse
|
|
{
|
|
$settings = $this->pluginSettingsService->get($identifier);
|
|
|
|
if ($settings === null) {
|
|
return $this->notFound('plugins.not_found');
|
|
}
|
|
|
|
return $this->success('messages.success', $this->maskSensitive($identifier, $settings));
|
|
}
|
|
|
|
/**
|
|
* 플러그인 설정을 업데이트합니다.
|
|
*
|
|
* @param UpdatePluginSettingsRequest $request 검증된 요청
|
|
* @param string $identifier 플러그인 식별자
|
|
* @return JsonResponse 업데이트 결과
|
|
*/
|
|
public function update(UpdatePluginSettingsRequest $request, string $identifier): JsonResponse
|
|
{
|
|
// 검증을 통과한 필드만 저장한다. 과거에는 validated() 가 비면 all() 로 폴백했으나,
|
|
// 그 명분이던 "PluginManager 미등록 플러그인" 은 PluginSettingsService::save() 가
|
|
// 이미 false 로 차단하므로 도달할 수 없었고, 실제로는 설정 스키마 밖의 키가
|
|
// 그대로 설정 파일에 병합되는 경로로만 동작했다 (mass-assignment).
|
|
$settings = $request->validated();
|
|
|
|
$result = $this->pluginSettingsService->save($identifier, $settings);
|
|
|
|
if (! $result) {
|
|
return $this->error('plugins.settings.update_failed', 500);
|
|
}
|
|
|
|
return $this->success(
|
|
'plugins.settings.updated',
|
|
$this->maskSensitive($identifier, $this->pluginSettingsService->get($identifier) ?? [])
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 플러그인 설정 레이아웃을 조회합니다.
|
|
*
|
|
* 설정 페이지 UI 구성과 설정 스키마를 반환합니다.
|
|
*
|
|
* @param string $identifier 플러그인 식별자
|
|
* @return JsonResponse 레이아웃 데이터
|
|
*/
|
|
public function layout(string $identifier): JsonResponse
|
|
{
|
|
$layout = $this->pluginSettingsService->getLayout($identifier);
|
|
|
|
if ($layout === null) {
|
|
return $this->notFound('plugins.not_found');
|
|
}
|
|
|
|
return $this->success('messages.success', $layout);
|
|
}
|
|
}
|