v7.0.0 release
This commit is contained in:
@@ -2,16 +2,19 @@
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Exceptions\ModuleOperationException;
|
||||
use App\Contracts\Extension\ModuleManagerInterface;
|
||||
use App\Contracts\Repositories\ModuleRepositoryInterface;
|
||||
use App\Enums\ExtensionStatus;
|
||||
use App\Exceptions\ModuleOperationException;
|
||||
use App\Extension\Helpers\ChangelogParser;
|
||||
use App\Extension\Helpers\EditorSpecAssembler;
|
||||
use App\Extension\Helpers\GithubHelper;
|
||||
use App\Extension\Helpers\ZipInstallHelper;
|
||||
use App\Extension\HookManager;
|
||||
use App\Extension\Vendor\VendorMode;
|
||||
use App\Helpers\PermissionHelper;
|
||||
use App\Models\Module;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
@@ -102,7 +105,7 @@ class ModuleService
|
||||
/**
|
||||
* 설치된 모듈 목록을 조회합니다.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Collection 설치된 모듈 목록
|
||||
* @return Collection 설치된 모듈 목록
|
||||
*/
|
||||
public function getInstalledModules()
|
||||
{
|
||||
@@ -112,7 +115,7 @@ class ModuleService
|
||||
/**
|
||||
* 마켓플레이스에서 이용 가능한 모듈 목록을 조회합니다.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Collection 마켓플레이스 모듈 목록
|
||||
* @return Collection 마켓플레이스 모듈 목록
|
||||
*/
|
||||
public function getMarketplaceModules()
|
||||
{
|
||||
@@ -122,7 +125,7 @@ class ModuleService
|
||||
/**
|
||||
* 의존성 정보가 포함된 모든 모듈을 조회합니다.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Collection 의존성 정보가 포함된 모듈 목록
|
||||
* @return Collection 의존성 정보가 포함된 모듈 목록
|
||||
*/
|
||||
public function getAllModulesWithDependencies()
|
||||
{
|
||||
@@ -169,17 +172,16 @@ class ModuleService
|
||||
* 지정된 모듈을 업데이트합니다.
|
||||
*
|
||||
* @param string $moduleName 업데이트할 모듈 identifier
|
||||
* @param \App\Extension\Vendor\VendorMode $vendorMode Vendor 설치 모드
|
||||
* @param VendorMode $vendorMode Vendor 설치 모드
|
||||
* @param string $layoutStrategy 레이아웃 전략 (overwrite|keep)
|
||||
* @return array 업데이트 결과 (identifier, from_version, to_version 등)
|
||||
*
|
||||
* @param bool $force 코어 버전 비호환 강제 우회 (위험 — 사용자 명시 필요)
|
||||
* @return array 업데이트 결과 (identifier, from_version, to_version 등)
|
||||
*
|
||||
* @throws ValidationException 업데이트 실패 시
|
||||
*/
|
||||
public function updateModule(
|
||||
string $moduleName,
|
||||
\App\Extension\Vendor\VendorMode $vendorMode = \App\Extension\Vendor\VendorMode::Auto,
|
||||
VendorMode $vendorMode = VendorMode::Auto,
|
||||
string $layoutStrategy = 'overwrite',
|
||||
bool $force = false,
|
||||
): array {
|
||||
@@ -238,7 +240,7 @@ class ModuleService
|
||||
* 모듈을 시스템에 설치합니다.
|
||||
*
|
||||
* @param string $moduleName 설치할 모듈명
|
||||
* @param \App\Extension\Vendor\VendorMode $vendorMode Vendor 설치 모드
|
||||
* @param VendorMode $vendorMode Vendor 설치 모드
|
||||
* @param bool $force Updating/Failed 등 진행 중 상태도 무시하고 강제 설치 여부
|
||||
* @return array|null 설치된 모듈 정보 또는 null
|
||||
*
|
||||
@@ -246,7 +248,7 @@ class ModuleService
|
||||
*/
|
||||
public function installModule(
|
||||
string $moduleName,
|
||||
\App\Extension\Vendor\VendorMode $vendorMode = \App\Extension\Vendor\VendorMode::Auto,
|
||||
VendorMode $vendorMode = VendorMode::Auto,
|
||||
bool $force = false,
|
||||
): ?array {
|
||||
HookManager::doAction('core.modules.before_install', $moduleName);
|
||||
@@ -736,6 +738,7 @@ class ModuleService
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 업로드된 ZIP 파일로부터 모듈을 추출/검증하고 _pending 으로 이동 후 설치합니다.
|
||||
*
|
||||
@@ -950,6 +953,83 @@ class ModuleService
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 모듈 편집기 스펙(editor-spec.json) 디코드 결과를 반환합니다.
|
||||
*
|
||||
* 활성 모듈만 대상으로 하며, 활성 디렉토리 → _bundled 폴백 순으로 읽습니다.
|
||||
* editor-spec.json 은 수작업 작성 파일로 모듈 루트(module.json 옆)에 둡니다.
|
||||
* 파일 미존재/미작성 시 spec=null 로 폴백합니다(편집 컨트롤 부재).
|
||||
*
|
||||
* @param string $identifier 모듈 식별자 (vendor-module 형식)
|
||||
* @return array{success: bool, spec: array<string, mixed>|null, error: string|null}
|
||||
*/
|
||||
public function getEditorSpec(string $identifier): array
|
||||
{
|
||||
$module = $this->moduleRepository->findByIdentifier($identifier);
|
||||
|
||||
if (! $module || $module->status !== ExtensionStatus::Active->value) {
|
||||
return ['success' => false, 'spec' => null, 'error' => 'module_not_found'];
|
||||
}
|
||||
|
||||
// 분할 editor-spec.json 은 manifest + `$include` 블록으로 구성되므로
|
||||
// 단순 디코드가 아닌 합본이 필요하다. 활성 디렉토리만 기준으로 합본한다
|
||||
// (_bundled 폴백 없음). _bundled 작업분은 module:update 로 활성에
|
||||
// 반영된 뒤에만 런타임에 보인다. 미분할 파일은 원본 그대로(하위 호환).
|
||||
$spec = EditorSpecAssembler::assemble(
|
||||
base_path("modules/{$identifier}/editor-spec.json")
|
||||
);
|
||||
|
||||
return ['success' => true, 'spec' => $spec, 'error' => null];
|
||||
}
|
||||
|
||||
/**
|
||||
* 모듈 컴포넌트 매니페스트(components.json) 디코드 결과를 반환합니다.
|
||||
*
|
||||
* components.json 은 module:build 산출물로 모듈 루트에 둡니다.
|
||||
* 활성 디렉토리 → _bundled 폴백 순으로 읽으며, 미생성(구버전 모듈) 시
|
||||
* components=null 로 폴백합니다(무손실 보존 디그레이드 — 원칙 4.6).
|
||||
*
|
||||
* @param string $identifier 모듈 식별자
|
||||
* @return array{success: bool, components: array<string, mixed>|null, error: string|null}
|
||||
*/
|
||||
public function getComponents(string $identifier): array
|
||||
{
|
||||
$module = $this->moduleRepository->findByIdentifier($identifier);
|
||||
|
||||
if (! $module || $module->status !== ExtensionStatus::Active->value) {
|
||||
return ['success' => false, 'components' => null, 'error' => 'module_not_found'];
|
||||
}
|
||||
|
||||
$components = $this->readJsonWithBundledFallback("modules/{$identifier}/components.json");
|
||||
|
||||
return ['success' => true, 'components' => $components, 'error' => null];
|
||||
}
|
||||
|
||||
/**
|
||||
* 활성 디렉토리 → _bundled 폴백 순으로 JSON 파일을 읽어 디코드합니다.
|
||||
*
|
||||
* @param string $relativePath base_path 기준 상대 경로 (modules/{id}/file.json)
|
||||
* @return array<string, mixed>|null 디코드된 배열, 미존재/파싱 실패 시 null
|
||||
*/
|
||||
private function readJsonWithBundledFallback(string $relativePath): ?array
|
||||
{
|
||||
// modules/{id}/file.json → modules/_bundled/{id}/file.json 폴백
|
||||
$bundledPath = preg_replace('#^modules/#', 'modules/_bundled/', $relativePath, 1);
|
||||
$candidates = [base_path($relativePath), base_path((string) $bundledPath)];
|
||||
|
||||
foreach ($candidates as $path) {
|
||||
if (! file_exists($path) || ! is_file($path)) {
|
||||
continue;
|
||||
}
|
||||
$decoded = json_decode((string) file_get_contents($path), true);
|
||||
if (is_array($decoded)) {
|
||||
return $decoded;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* MIME 타입 감지
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user