Files
par/par-api/src/main/java/com/par/api/controller/ScriptController.java
2026-07-06 00:11:40 +08:00

151 lines
6.7 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.par.api.controller;
import com.par.core.adapter.GroovyScriptEngine;
import com.par.core.dto.ApiResponse;
import com.par.core.entity.SiteConfig;
import com.par.core.entity.Site;
import com.par.core.mapper.SiteMapper;
import com.par.core.service.ConfigService;
import com.par.core.storage.CachedStorageService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* Groovy 脚本接口(mediabot 使用)
*/
@Slf4j
@RestController
@RequiredArgsConstructor
public class ScriptController {
private final ConfigService configService;
private final CachedStorageService storageService;
private final SiteMapper siteMapper;
private final com.par.core.mapper.SiteConfigMapper siteConfigMapper;
/** 下载最新 Groovy 脚本 */
@GetMapping("/api/v1/scripts/{siteId}")
public ResponseEntity<String> downloadScript(@PathVariable String siteId) {
SiteConfig latest = configService.getLatestConfig(siteId);
// 优先自定义脚本
if (latest != null && latest.getScriptStoragePath() != null
&& !latest.getScriptStoragePath().isBlank()) {
try {
String script = storageService.read(latest.getScriptStoragePath());
if (script != null && !script.isBlank()) {
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, "text/plain;charset=UTF-8")
.body(script);
}
} catch (Exception ignored) {}
}
// 回退到默认模板
var site = siteMapper.selectBySiteId(siteId);
String siteType = site != null && site.getSiteType() != null
? site.getSiteType().getValue() : null;
String defaultScript = GroovyScriptEngine.loadDefaultByType(siteType);
if (defaultScript != null) {
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, "text/plain;charset=UTF-8")
.body(defaultScript);
}
return ResponseEntity.notFound().build();
}
/** 删除站点自定义脚本(回退到默认模板) */
@DeleteMapping("/api/v1/admin/configs/{siteId}/script")
public ApiResponse<Void> deleteScript(@PathVariable String siteId, HttpServletRequest request) {
checkAdmin(request);
SiteConfig latest = configService.getLatestConfig(siteId);
if (latest == null) return ApiResponse.success();
latest.setScriptStoragePath(null);
latest.setIsLatest(false);
siteConfigMapper.updateById(latest);
log.info("Custom script deleted for siteId={}, fallback to default", siteId);
return ApiResponse.success();
}
/** 获取脚本版本(自定义脚本优先,否则返回默认模板版本) */
@GetMapping("/api/v1/scripts/{siteId}/version")
public ApiResponse<Map<String, String>> getVersion(@PathVariable String siteId) {
SiteConfig latest = configService.getLatestConfig(siteId);
if (latest != null && latest.getScriptStoragePath() != null && !latest.getScriptStoragePath().isBlank()) {
return ApiResponse.success(Map.of("version", latest.getVersion(), "source", "custom"));
}
// 回退到默认模板版本
var site = siteMapper.selectBySiteId(siteId);
String siteType = site != null && site.getSiteType() != null ? site.getSiteType().getValue() : null;
int defVer = GroovyScriptEngine.getDefaultVersion(siteType);
return ApiResponse.success(Map.of("version", String.valueOf(defVer), "source", "default"));
}
/** 获取站点类型默认脚本(管理员) */
@GetMapping("/api/v1/admin/scripts/default/{siteType}")
public ApiResponse<Map<String, String>> getDefaultScript(@PathVariable String siteType, HttpServletRequest request) {
checkAdmin(request);
String script = GroovyScriptEngine.loadDefaultByType(siteType);
int version = GroovyScriptEngine.getDefaultVersion(siteType);
return ApiResponse.success(Map.of("siteType", siteType, "script", script != null ? script : "", "version", String.valueOf(version)));
}
/** 保存站点类型默认脚本到本地 */
@PutMapping("/api/v1/admin/scripts/default/{siteType}/save")
public ApiResponse<Void> saveDefaultScript(
@PathVariable String siteType,
@RequestBody Map<String, String> payload,
HttpServletRequest request) {
checkAdmin(request);
String script = payload.get("script");
if (script == null || script.isBlank()) return ApiResponse.error(400, "script is required");
GroovyScriptEngine.saveDefaultLocal(siteType, script);
return ApiResponse.success();
}
/** 上传站点类型默认脚本到七牛云 */
@PutMapping("/api/v1/admin/scripts/default/{siteType}/upload")
public ApiResponse<Void> uploadDefaultScript(
@PathVariable String siteType,
@RequestBody Map<String, String> payload,
HttpServletRequest request) {
checkAdmin(request);
String script = payload.get("script");
if (script == null || script.isBlank()) return ApiResponse.error(400, "script is required");
GroovyScriptEngine.saveDefaultScript(siteType, script);
return ApiResponse.success();
}
private void checkAdmin(HttpServletRequest request) {
var level = request.getAttribute("trustLevel");
if (level == null || !"ADMIN".equals(level.toString())) {
throw new IllegalArgumentException("Admin permission required");
}
}
/** 上传 Groovy 脚本(PSK 签名认证) */
@PutMapping("/api/v1/scripts/{siteId}")
public ApiResponse<?> uploadScript(
@PathVariable String siteId,
@RequestBody String script,
HttpServletRequest request) {
if (script == null || script.isBlank()) {
return ApiResponse.error(400, "script body is required");
}
// 版本号递增
SiteConfig latest = configService.getLatestConfig(siteId);
int nextVersion = 1;
if (latest != null) {
try { nextVersion = Integer.parseInt(latest.getVersion()) + 1; }
catch (NumberFormatException ignored) {}
}
Long submitterId = (Long) request.getAttribute("accountId");
SiteConfig config = configService.submitConfig(siteId, String.valueOf(nextVersion), script, submitterId);
return ApiResponse.success(Map.of("version", config.getVersion()));
}
}