diff --git a/app/Http/Controllers/Api/Nasa/V1/ArticleBaseController.php b/app/Http/Controllers/Api/Nasa/V1/ArticleBaseController.php
new file mode 100755
index 0000000..e42be1b
--- /dev/null
+++ b/app/Http/Controllers/Api/Nasa/V1/ArticleBaseController.php
@@ -0,0 +1,112 @@
+ 'id',
+ 'user_name' => 'user_name',
+ 'project_name'=> 'project_name',
+ 'mail_name' => 'mail_name',
+ 'mail_tail' => 'mail_tail',
+ 'sale_code' => 'sale_code',
+ 'sale_rate' => 'sale_rate',
+ 'sale_price' => 'sale_price',
+ 'i_in10' => 'i_in10',
+ 'inday_count' => 'inday_count',
+ 'cron_condition' => 'cron_condition',
+ 'mod' => 'mod',
+ 'mod_type' => 'mod_type',
+ 'status' => 'status',
+ 'memo' => 'memo',
+ 'ship_code' => 'ship_code',
+ 'fn_www' => 'fn_www',
+ 'show_huodong' => 'show_huodong',
+ 'show_error' => 'show_error',
+// 'updated_at' => 'updated_at',
+// 'created_at' => 'created_at'
+ ];
+
+ protected array $aValueStyle = [ // 特定文字渲染样式
+// '关闭' => "关闭",
+// '开启' => "开启"
+ ];
+
+ protected array $aFieldTypes = [
+// 'schema' => 'text',
+// 'schema_pro' => 'text',
+// 'cmd' => 'text',
+// 'cmd_log' => 'text',
+// 'opt' => 'text'
+ ];
+
+ protected array $aOrderBy = [
+ [
+ "sField" => "id",
+ "sSort" => "desc",
+ ]
+ ];
+
+ protected array $aJsonFields = [ // json字段
+// 'schema'
+ ];
+
+ protected array $aDateFields = [ // date字段
+// 'dtUpdatedAt'
+ ];
+
+ protected array $aLenthFields = [ // 限制长度的字段
+// "xx" => 100,
+ ];
+
+ protected array $aSelectFields = [ // 作为默认select的字段
+// 'status',
+ ];
+
+ protected array $aValueFields = [ // 值映射
+// 'status' => [
+// '1' => '开启',
+// '0' => '关闭',
+// ]
+ ];
+
+ protected array $aCcExtFields = [
+// 'dtCreatedAt' => '创建时间'
+ ];
+
+// protected array $aLimit = [3, 15, 40, 100]; // list长度,第一个为默认
+
+// public function syncSave(Request $oRequest)
+// {
+// $id = request('id');
+// $siteGroupCode = request('siteGroupCode');
+// $cmd = request('type');
+//
+// $aParam['aOption'][1] = $id;
+// $aParam['aArg'][1] = $siteGroupCode;
+// $aParam['aArg'][2] = $cmd;
+// $oArma = new Arma([]);
+// $r = $oArma->cmd($aParam, []);
+//
+// return response()->json([
+// 'iCode' => 200,
+// 'aData' => [],
+// 'sMsg' => $r
+// ], 200);
+//
+// }
+}
diff --git a/app/Http/Controllers/Api/Nasa/V1/Base/ListController.php b/app/Http/Controllers/Api/Nasa/V1/Base/ListController.php
new file mode 100755
index 0000000..afaaa86
--- /dev/null
+++ b/app/Http/Controllers/Api/Nasa/V1/Base/ListController.php
@@ -0,0 +1,500 @@
+ [],
+ 'cc' => [],
+ 'ob' => [],
+ ];
+
+ protected $oModel;
+ protected array $aValueFields = [];
+ protected string $sPageName = '';
+// protected string $sModelName = '';
+ protected string $sModelPath = '';
+ protected array $aFilterFields = []; // 允许where的字段
+// protected array $aArticleFields = []; // 文章字段
+ protected array $aFieldTypes = [];
+ protected array $aLenthFields = []; // 限制长度的字段
+ protected array $aSelectFields = []; // 默认作为select的字段
+ protected array $aListFields = []; // list展示的字段和名字映射
+ protected array $aDateFields = []; // date字段
+ protected array $aJsonFields = []; // json字段
+// protected array $aValueStyle = []; // 特定文字渲染样式
+ protected int $iLimitMax = 100; // 默认limit限制
+ protected int $iLimit = 20; // 默认显示行数
+ protected array $aCcExtFields = []; // 自定义条件字段追加在listFields后
+ protected array $aCcFields = [];
+ protected int $iOrderByMax = 3;
+ protected array $aOrderBy = [
+ [
+ "sField" => "id",
+ "sSort" => "desc"
+ ]
+ ];
+ protected array $aValueStyle = [ // 特定文字渲染样式
+ '关闭' => "关闭",
+ '开启' => "开启"
+ ];
+
+ public function __construct()
+ {
+ if ($this->sModelPath) {
+ if (! class_exists($this->sModelPath)) {
+ throw new InvalidArgumentException("【系统架构错误】: 找不到领域模型 {$this->sModelPath}");
+ }
+
+ $this->oModel = new $this->sModelPath();
+ $this->aCcFields = array_merge($this->aListFields, $this->aCcExtFields);
+ $this->aCcFields = $this->getCcFields();
+ }
+ }
+
+ private function getCcFields()
+ {
+ $a = [];
+ foreach ($this->aCcFields as $k => $v) {
+ if (is_array($v)) {
+ foreach ($v as $kk => $vv) {
+ $a[$kk] = $vv;
+ }
+ } else {
+ $a[$k] = $v;
+ }
+ }
+
+ return $a;
+ }
+
+ private function mapOperator($sOperator)
+ {
+ $sSqlOperator = match ($sOperator) {
+ 'like' => 'like',
+ 'eq' => '=',
+ 'ne' => '!=',
+ 'gt' => '>',
+ 'gte' => '>=',
+ 'lt' => '<',
+ 'lte' => '<=',
+ default => '',
+ };
+
+ return $sSqlOperator;
+ }
+
+ private function getOrderBySchema()
+ {
+ $iOrderByCount = count($this->aOrderBy);
+ $iDiff = $this->iOrderByMax - $iOrderByCount;
+ $a = $this->aOrderBy;
+ for ($i=0; $i<$iDiff; $i++) {
+ $a[] = [];
+ }
+ return $a;
+ }
+
+ private function getOrderBy()
+ {
+ return $this->aOrderBy;
+ }
+
+ public function getListFields()
+ {
+ $a = [];
+
+ foreach ($this->aListFields as $k => $v) {
+ if ($v) {
+ $a[$k] = $v;
+ } else {
+ $a[$k] = $k;
+ }
+ }
+
+ return $a;
+ }
+
+ private function getCcLast()
+ {
+ $aCcFieldsTmp = $this->aCcFields;
+
+ foreach ($this->aFilterParams['cc'] as $ACC) {
+ unset($aCcFieldsTmp[$ACC['sField']]);
+ }
+
+ $s = head(array_keys($aCcFieldsTmp));
+
+ return $s;
+ }
+
+ public function add(Request $oRequest): \Illuminate\Http\JsonResponse
+ {
+ $sTableName = $this->oModel->getTable();
+ $aRawFields = Schema::getColumnListing($sTableName);
+
+ $sClassName = get_class($this->oModel);
+
+ $aKickFields = [];
+
+ if (defined($sClassName . '::UPDATED_AT')) {
+ $aKickFields[] = constant($sClassName . '::UPDATED_AT');
+ }
+
+ if (defined($sClassName . '::CREATED_AT')) {
+ $aKickFields[] = constant($sClassName . '::CREATED_AT');
+ }
+
+ $aKickFields[] = "id";
+
+ $aRawFieldsClear = [];
+ foreach ($aRawFields as $aRawField) {
+ if (in_array($aRawField, $aKickFields)) {
+ continue;
+ }
+ $aRawFieldsClear[] = $aRawField;
+ }
+
+ return response()->json([
+ 'iCode' => 200,
+ 'aData' => [
+ 'cList' => $aRawFieldsClear,
+ 'sPageName' => $this->sPageName
+ ]
+ ], 200);
+ }
+
+ public function clone(Request $oRequest)
+ {
+ $iId = request('id');
+ $oModelResult = $this->oModel->findOrFail($iId);
+ $cList = $oModelResult->getRawOriginal();
+
+ $sTableName = $this->oModel->getTable();
+ $aStatus = DB::select("SHOW TABLE STATUS LIKE '{$sTableName}'");
+ $iNextId = $aStatus[0]->Auto_increment ?? 1;
+
+ $cList['id'] = $iNextId;
+
+ return response()->json([
+ 'iCode' => 200,
+ 'aData' => [
+ 'cList' => $cList,
+ 'aMap' => $this->getMapAll(),
+ 'aListField' => $this->getListFields(),
+ 'sPageName' => $this->sPageName
+ ]
+ ], 200);
+ }
+
+// public function cloneSave(Request $oRequest)
+// {
+// $iId = request('id');
+//
+// $aParams = $oRequest->all();
+//
+// foreach ($aParams as $k => $v) {
+// $this->oModal->{$k} = $v;
+// }
+// $this->oModel->create();
+//
+// return response()->json([
+// 'iCode' => 200,
+// 'aData' => [],
+// 'sMsg' => "保存成功:id ".$this->oModel->id
+// ], 200);
+// }
+
+ public function detail(Request $oRequest)
+ {
+ $iId = request('id');
+ $oModelResult = $this->oModel->findOrFail($iId);
+ $cList = $oModelResult->getRawOriginal();
+
+ return response()->json([
+ 'iCode' => 200,
+ 'aData' => [
+ 'cList' => $cList,
+ 'aMap' => $this->getMapAll(),
+ 'aListField' => $this->getListFields(),
+ 'sPageName' => $this->sPageName
+ ]
+ ], 200);
+ }
+
+ public function hit(Request $oRequest)
+ {
+ $iId = request('id');
+ $sField = request('field');
+
+ $sFieldType = $this->aFieldTypes[$sField] ?? '';
+
+ $sHit = $this->oModel->find($iId)?->{$sField};
+ if (is_array($sHit)) {
+ $sHit = json_encode($sHit);
+ }
+
+ if ($sFieldType == 'json') {
+ $sHit = json_decode($sHit, true);
+ $sHit = json_encode($sHit, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+ }
+
+ return response()->json([
+ 'iCode' => 200,
+ 'aData' => [
+ 'sHit' => $sHit
+ ]
+ ], 200);
+
+ }
+
+ public function delete(Request $oRequest)
+ {
+ $iId = request('id');
+
+ $this->oModel->findOrFail($iId)->delete();
+
+ return response()->json([
+ 'iCode' => 200,
+ 'aData' => [],
+ 'sMsg' => '删除成功'
+ ], 200);
+ }
+
+ public function addSave(Request $oRequest)
+ {
+ $aParams = $oRequest->all();
+
+ foreach ($aParams as $k => $v) {
+ $this->oModel->{$k} = $v;
+ }
+
+ if (!$this->oModel->save()) {
+ return response()->json(['code' => 500, 'msg' => '保存失败?'], 500);
+ }
+
+ return response()->json([
+ 'iCode' => 200,
+ 'aData' => [],
+ 'sMsg' => '保存成功'
+ ], 200);
+ }
+
+ public function detailSave(Request $oRequest)
+ {
+ $iId = request('id');
+
+ $oThisModel = $this->oModel->find($iId);
+
+ $aParams = $oRequest->all();
+
+ unset($aParams['id'], $aParams['_method']);
+
+ foreach ($aParams as $k => &$v) {
+ if (empty($v) && empty($oThisModel->{$k})) {
+ continue;
+ }
+ if (empty($v) && $v !== 0 && $v !== '0') {
+ $v = '';
+ }
+ if ($oThisModel->{$k} != $v) {
+ $oThisModel->{$k} = $v;
+ }
+ }
+
+ $oThisModel->save();
+
+ $aChangeField = $oThisModel->getChanges();
+
+ /// 排除update_at
+ $sClassName = get_class($this->oModel);
+ if (
+ defined($sClassName . '::UPDATED_AT')
+ && ($sUpdateColumn = constant($sClassName . '::UPDATED_AT'))
+ && !isset($aParams[$sUpdateColumn])
+ && isset($aChangeField[$sUpdateColumn])
+ ) {
+ unset($aChangeField[$sUpdateColumn]);
+ }
+
+ /// 构造msg
+ $sMsg = "";
+ $sJiantou = " -> ";
+ foreach ($aChangeField as $k => $v) {
+
+ if (mb_strlen($v, 'UTF-8') > 60 ) {
+ $sJiantou = '';
+// $v = mb_substr($v, 0, 60, 'UTF-8');
+ $v = '';
+ }
+
+ if (!isset($aParams[$k])) {
+ $sMsg .= "⚠️ ".$k . $sJiantou . $v . "
";
+ } else {
+ $sMsg .= "✅ ".$k . $sJiantou . $v . "
";
+ unset($aParams[$k]);
+ }
+ }
+ foreach ($aParams as $k => $v) {
+
+ if (mb_strlen($v, 'UTF-8') > 60 ) {
+ $sJiantou = '';
+// $v = mb_substr($v, 0, 60, 'UTF-8');
+ $v = '';
+ }
+
+ $sMsg .= "❌ ".$k . $sJiantou . $v . "
";
+ }
+ $sMsg = rtrim($sMsg, "
");
+
+ return response()->json([
+ 'iCode' => 200,
+ 'aData' => $aChangeField,
+ 'sMsg' => $sMsg
+ ], 200);
+ }
+
+ public function getMapAll()
+ {
+ $a = [];
+
+ if (method_exists($this->oModel, 'getMapAll')) {
+ $a = $this->oModel->getMapAll();
+ }
+
+ $b = array_merge($a, $this->aValueFields);
+
+ return $b;
+ }
+
+ public function index(Request $oRequest)
+ {
+ if (! $this->oModel) {
+ return response()->json(['code' => 500, 'msg' => '未绑定核心领域模型'], 500);
+ }
+
+ $oQuery = $this->oModel->newQuery();
+
+ $aParams = $oRequest->all();
+
+ foreach ($aParams as $k => $v) {
+
+ if (!empty($this->aFilterFields)) {
+ if (!in_array($k, $this->aFilterFields)) {
+ continue;
+ }
+ }
+
+ // w__name__eq=1
+ $aK = explode("__", $k);
+ $sType = $aK[0] ?? '';
+ $sField = $aK[1] ?? '';
+ $sOperator = $aK[2] ?? $this->sOperatorDefault;
+ $sSqlOperator = $this->mapOperator($sOperator);
+
+ if (!isset($this->aFilterParams[$sType])) {
+ continue;
+ }
+
+ if (!$sType || !$sField) {
+ continue;
+ }
+
+ $this->aFilterParams[$k] = $v;
+
+ if ($sType === 'ob') {
+ $this->aFilterParams[$sType][] = [
+ 'sField' => $sField,
+ 'sSort' => $v ?? $this->sSortDefault
+ ];
+ continue;
+ }
+
+ if ($sType === 'c') { // 预制条件,字典式
+ $this->aFilterParams[$sType][$sField] = [
+ 'sOperator' => $sOperator,
+ 'sValue' => $v
+ ];
+ }
+
+ if ($sType === 'cc') { // 自定义条件,集合式
+ $this->aFilterParams[$sType][] = [
+ 'sField' => $sField,
+ 'sOperator' => $sOperator,
+ 'sValue' => $v
+ ];
+ }
+
+ if (blank($v)) continue; // 空v可以back但不加入sql查询
+
+ $sSqlValue = $v;
+ if ($sSqlOperator === 'like') {
+ $sSqlValue = "%{$v}%";
+ }
+
+ if (in_array($sField, $this->aDateFields)) {
+ $oQuery->whereDate($sField, $sSqlOperator, $sSqlValue);
+ } else {
+ $oQuery->where($sField, $sSqlOperator, $sSqlValue);
+ }
+
+ }
+
+ $iLimit = (int) $oRequest->input('limit', $this->iLimit);
+ $iLimit = max(1, $iLimit);
+ $iLimit = min($this->iLimitMax, $iLimit);
+
+ if (!empty($this->aFilterParams['ob'])) {
+ $this->aOrderBy = $this->aFilterParams['ob'];
+ }
+
+ foreach ($this->aOrderBy as $aOrderBy) {
+ $oQuery->orderBy($aOrderBy['sField'], $aOrderBy['sSort']);
+ }
+
+ $oPaginatedData = $oQuery->paginate($iLimit);
+// tt($oPaginatedData);
+// $oPaginatedData = $oQuery->paginate($iLimit, array_keys($this->aListFields));
+
+ return response()->json([
+ 'iCode' => 200,
+ 'aData' => [
+ 'cList' => $oPaginatedData->items(),
+ 'aListField' => $this->getListFields(),
+ 'aFieldTypes' => $this->aFieldTypes,
+ 'aMap' => $this->getMapAll(),
+ 'aValueStyle' => $this->aValueStyle,
+ 'aSelectField' => $this->aSelectFields,
+ 'aFilterParam' => $this->aFilterParams,
+ 'aCcField' => $this->aCcFields,
+ 'sCcLast' => $this->getCcLast(),
+ 'sPageName' => $this->sPageName,
+ 'aPager' => [
+ 'aOrderBySchema'=> $this->getOrderBySchema(),
+ 'aOrderBy' => $this->getOrderBy(),
+ 'iTotal' => $oPaginatedData->total(),
+ 'iLimit' => min($this->iLimitMax, $iLimit),
+ 'iCurrentPage' => $oPaginatedData->currentPage(),
+ 'iLastPage' => $oPaginatedData->lastPage(),
+ 'iPerPage' => $oPaginatedData->perPage(),
+ 'iPrevPage' => max(1, $oPaginatedData->currentPage() - 1),
+ 'iNextPage' => min($oPaginatedData->lastPage(), $oPaginatedData->currentPage() + 1)
+ ]
+ ]
+ ], 200);
+
+ }
+
+}
diff --git a/app/Http/Controllers/CronController.php b/app/Http/Controllers/CronController.php
index 07bb594..0922109 100755
--- a/app/Http/Controllers/CronController.php
+++ b/app/Http/Controllers/CronController.php
@@ -246,6 +246,13 @@ class CronController
}
+ // 没有文件夹,创建一个
+ if (!is_dir($this->sProjectPath."/feed")) {
+
+ mkdir($this->sProjectPath."/feed", 0755, true);
+
+ }
+
// 没有仓库,创建一个
if (!is_dir($this->sProjectPath . "/.git")) {
diff --git a/app/Http/Middleware/VerifyNasaToken.php b/app/Http/Middleware/VerifyNasaToken.php
new file mode 100644
index 0000000..6a9745b
--- /dev/null
+++ b/app/Http/Middleware/VerifyNasaToken.php
@@ -0,0 +1,49 @@
+input(),全面改用 ->header() 降维打击!
+ // 🎯 核心微操:Laravel 的 header() 方法天生自带防抖,它对大小写不敏感,
+ // 你传 'X-Nasa-Token' 或者 'x-nasa-token',底层都能稳稳咬住!
+ $iRequestTime = (int)$oRequest->header('X-Nasa-Timestamp');
+ $sClientToken = $oRequest->header('X-Nasa-Token');
+
+ // 1. 钢铁防御线一:前置空值熔断,连参数都没有的盲流直接当场轰杀
+ if (!$iRequestTime || !$sClientToken) {
+ return response()->json(['iStatus' => 0, 'sMsg' => 'Security Headers Missing'], 403);
+ }
+
+ // 2. 时效性防御:前后端时间差超过 60 秒判定为重放攻击或过期
+ if (abs(time() - $iRequestTime) > 60) {
+ Log::warning("🛰️ NASA 网关拦截:请求超时已过期!当前服务器时间: " . time() . ",请求时间: {$iRequestTime}");
+ return response()->json(['iStatus' => 0, 'sMsg' => 'Request Expired'], 403);
+ }
+
+ // 3. 验签防御:从配置核心仓掏出密钥,用相同算法重算 Token 对比
+ $sLocalSecret = config('nasa.secret');
+ $sExpectedToken = md5("timestamp={$iRequestTime}&secret={$sLocalSecret}");
+
+ // 4. 钢铁防御线二:像素级对撞签名
+ if ($sClientToken !== $sExpectedToken) {
+ $s = "🚨 NASA 网关警报:发现非法伪造签名!客户端传值: {$sClientToken},期望值: {$sExpectedToken}";
+ Log::error($s);
+ return response()->json(['iStatus' => 0, 'sMsg' => $s], 403);
+ }
+
+ // 5. 安全放行,通电!
+ return $fNext($oRequest);
+ }
+}
diff --git a/bootstrap/app.php b/bootstrap/app.php
index adb2b31..0aeaf38 100755
--- a/bootstrap/app.php
+++ b/bootstrap/app.php
@@ -11,10 +11,18 @@ return Application::configure(basePath: dirname(__DIR__))
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
- ->withMiddleware(function (Middleware $middleware) {
-// $middleware->alias([
-// 'test' => \App\Http\Middleware\Test::class,
+// ->withMiddleware(function (Middleware $middleware) {
+//// $middleware->alias([
+//// 'test' => \App\Http\Middleware\Test::class,
+//// ]);
+// $middleware->validateCsrfTokens(except: [
+// 'api/*',
// ]);
+// })
+ ->withMiddleware(function (Middleware $middleware) {
+ $middleware->alias([
+ 'nasa.auth' => \App\Http\Middleware\VerifyNasaToken::class,
+ ]);
$middleware->validateCsrfTokens(except: [
'api/*',
]);
diff --git a/config/nasa.php b/config/nasa.php
new file mode 100755
index 0000000..ccbb264
--- /dev/null
+++ b/config/nasa.php
@@ -0,0 +1,6 @@
+ env('NASA_API_SECRET'),
+ 'verify_ssl' => env('NASA_API_VERIFY_SSL', true),
+];
diff --git a/just/tom无脑流程.text b/just/tom无脑流程.text
index b23a2cf..8bf1a5e 100644
--- a/just/tom无脑流程.text
+++ b/just/tom无脑流程.text
@@ -100,7 +100,24 @@ sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo certbot --nginx
-========nginx配置================
+=============添加拉取仓库流程==================
+
+先走通标准流程,会自动init,生成fn和vertion那些传上去。
+
+然后:
+ git remote add tom https://gitea.diaodu.us/tom/github-pachong.git - 添加拉取地址,tom是自定义名字
+ git config --global --add safe.directory /www/wwwroot/github-6.diaodu.us/github/xibanyahu-phppachong - 附加
+ git pull tom master
+ git reset --hard tom/master - 覆盖切换
+ chown www-data:www-data * - 老活
+ 然后/test#cron__id 1,不出意外就通了
+
+之后每次拉取都:
+ git pull tom master
+ git reset --hard tom/master
+
+
+=============nginx配置========================
server {
listen 80;
@@ -137,6 +154,8 @@ iphonevpn clash telegram nefilx vpn vless clashmeta vmess surge ssr
======
+sudo -u www-data git push -u origin main --force
+
{
"id": 1,
"user_name": "jichangtuijian99", // github的username
@@ -160,22 +179,23 @@ iphonevpn clash telegram nefilx vpn vless clashmeta vmess surge ssr
}
{
- "user_name": "xibanyahu",
- "project_name": "xibanyahu.github.io",
- "mail_name": "xibanyahu",
+ "id": 1,
+ "user_name": "danmaifu",
+ "project_name": "mianfeijiedian",
+ "mail_name": "erdama123",
"mail_tail": "outlook.com",
- "sale_code": "clashfreenode.com",
+ "sale_code": "clashv2rayfree.com",
"sale_rate": 7,
"sale_price": 8,
"i_in10": "false",
- "inday_count": 3,
+ "inday_count": 4,
"cron_condition": "false",
- "mod": "test",
+ "mod": "fn_c",
"mod_type": "blade",
"status": 1,
"memo": "",
- "ship_code": "fuuuu",
+ "ship_code": "fuuu",
"fn_www": "clashfreenode.com",
- "show_huodong": 0,
+ "show_huodong": 1,
"show_error": 1
}
diff --git a/routes/api.php b/routes/api.php
index 292041a..c544d72 100755
--- a/routes/api.php
+++ b/routes/api.php
@@ -6,7 +6,7 @@ use Illuminate\Support\Facades\Route;
//use App\Http\Controllers\CronController;
//use App\Http\Controllers\TestsController;
use App\Http\Controllers\Api\Tg\HookController;
-
+use App\Http\Controllers\Api\Nasa\V1\ArticleBaseController as NasaV1ArticleBaseController;
//Route::post('/api/tg/hook', [HookController::class, 'cmd']);
@@ -15,3 +15,20 @@ use App\Http\Controllers\Api\Tg\HookController;
// Route::post('/api/tg/hook', [HookController::class, 'cmd']);
//});
+
+Route::prefix('nasa/v1')->middleware('nasa.auth')->group(function () {
+
+ Route::prefix('article/base')->group(function() {
+ Route::get('', [NasaV1ArticleBaseController::class, 'index']);
+ Route::get('detail/{id}', [NasaV1ArticleBaseController::class, 'detail']);
+ Route::put('detail/save/{id}', [NasaV1ArticleBaseController::class, 'detailSave']);
+ Route::delete('delete/{id}', [NasaV1ArticleBaseController::class, 'delete']);
+ Route::get('add', [NasaV1ArticleBaseController::class, 'add']);
+ Route::put('add/save', [NasaV1ArticleBaseController::class, 'addSave']);
+ Route::get('clone/{id}', [NasaV1ArticleBaseController::class, 'clone']);
+ Route::put('clone/save', [NasaV1ArticleBaseController::class, 'cloneSave']);
+ Route::get('hit/{id}/{field}', [NasaV1ArticleBaseController::class, 'hit']);
+ });
+
+});
+