Move Custom Scripts out of the repo and add an Import Script picker
Custom Scripts (the Scheduler page's inline editor) used to save into the git-tracked Custom/ folder, so anything saved there would end up on GitHub. They now live in /boot/config/plugins/user.scripts/Varaverk/Scripts, same folder family as Unraid's own User Scripts plugin. Import Script lets you browse the whole server and move an existing script in instead of only creating new ones inline — always a move, never a copy, so no stray duplicate is left where it came from.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
// Import Script — lets the Scheduler page's "+ Import Script" browser move an existing
|
||||
// .sh file from anywhere on the server into CUSTOM_SCRIPTS_DIR. This is a MOVE: the
|
||||
// source is deleted once the copy is verified, so no stale duplicate is left behind.
|
||||
header('Content-Type: application/json');
|
||||
header('Cache-Control: no-store, no-cache');
|
||||
require_once dirname(__DIR__) . '/include/config.php';
|
||||
|
||||
// ── browse (GET): list subdirectories and .sh files at $path, rooted at / ─────
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET' && ($_GET['action'] ?? '') === 'browse') {
|
||||
$path = trim($_GET['path'] ?? '/');
|
||||
if (!preg_match('#^/[^\0]*$#', $path) || str_contains($path, '..')) {
|
||||
echo json_encode(['ok' => false, 'error' => 'Invalid path']);
|
||||
exit;
|
||||
}
|
||||
$clean = rtrim($path, '/') ?: '/';
|
||||
if (!is_dir($clean)) {
|
||||
echo json_encode(['ok' => false, 'error' => 'Not a directory: ' . $clean]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$dirOut = shell_exec('find ' . escapeshellarg($clean) . ' -maxdepth 1 -mindepth 1 -type d 2>/dev/null | sort | head -300') ?: '';
|
||||
$dirs = array_values(array_filter(array_map('trim', explode("\n", $dirOut))));
|
||||
|
||||
$fileOut = shell_exec('find ' . escapeshellarg($clean) . ' -maxdepth 1 -mindepth 1 -type f -iname "*.sh" 2>/dev/null | sort | head -300') ?: '';
|
||||
$files = array_values(array_filter(array_map('trim', explode("\n", $fileOut))));
|
||||
|
||||
$parent = ($clean !== '/') ? (dirname($clean) ?: '/') : null;
|
||||
echo json_encode(['ok' => true, 'path' => $clean, 'dirs' => $dirs, 'files' => $files, 'parent' => $parent]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// ── import (POST): move the chosen .sh file into CUSTOM_SCRIPTS_DIR ───────────
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'import') {
|
||||
$src = trim($_POST['path'] ?? '');
|
||||
if (!preg_match('#^/[^\0]*\.sh$#i', $src) || str_contains($src, '..')) {
|
||||
echo json_encode(['ok' => false, 'error' => 'Invalid script path']);
|
||||
exit;
|
||||
}
|
||||
if (!is_file($src)) {
|
||||
echo json_encode(['ok' => false, 'error' => 'Not found: ' . $src]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$srcReal = realpath($src);
|
||||
if ($srcReal === false) {
|
||||
echo json_encode(['ok' => false, 'error' => 'Could not resolve path']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Refuse to move a file out of the git-tracked repo — that would delete a
|
||||
// tracked file out from under git without a commit recording it.
|
||||
$repoReal = realpath(SCRIPTS_DIR);
|
||||
if ($repoReal && str_starts_with($srcReal, $repoReal . '/')) {
|
||||
echo json_encode(['ok' => false, 'error' => 'Refusing to import from inside the Varaverk repo — that would delete a git-tracked file.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Already there — nothing to do.
|
||||
$customReal = realpath(CUSTOM_SCRIPTS_DIR) ?: CUSTOM_SCRIPTS_DIR;
|
||||
if (str_starts_with($srcReal, rtrim($customReal, '/') . '/')) {
|
||||
echo json_encode(['ok' => false, 'error' => 'Already in Custom Scripts.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!is_dir(CUSTOM_SCRIPTS_DIR)) mkdir(CUSTOM_SCRIPTS_DIR, 0755, true);
|
||||
|
||||
$name = basename($srcReal);
|
||||
$dest = CUSTOM_SCRIPTS_DIR . '/' . $name;
|
||||
if (file_exists($dest)) {
|
||||
echo json_encode(['ok' => false, 'error' => "A script named \"$name\" already exists in Custom Scripts."]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Copy across filesystems, verify, THEN delete the source — never remove the
|
||||
// only copy on a failed or partial copy.
|
||||
if (!copy($srcReal, $dest)) {
|
||||
@unlink($dest);
|
||||
echo json_encode(['ok' => false, 'error' => 'Copy failed']);
|
||||
exit;
|
||||
}
|
||||
if (filesize($srcReal) !== filesize($dest) || hash_file('sha256', $srcReal) !== hash_file('sha256', $dest)) {
|
||||
@unlink($dest);
|
||||
echo json_encode(['ok' => false, 'error' => 'Copy verification failed — source left untouched']);
|
||||
exit;
|
||||
}
|
||||
chmod($dest, 0755);
|
||||
|
||||
if (!@unlink($srcReal)) {
|
||||
// Copied and verified but couldn't remove the original (permissions, read-only
|
||||
// mount). The script is usable from its new home either way — surface a warning
|
||||
// rather than failing the import outright.
|
||||
echo json_encode([
|
||||
'ok' => true,
|
||||
'id' => 'Custom/' . $name,
|
||||
'warning' => 'Imported, but could not delete the original at ' . $srcReal . ' — remove it manually.',
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode(['ok' => true, 'id' => 'Custom/' . $name]);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode(['ok' => false, 'error' => 'Invalid request']);
|
||||
@@ -8,7 +8,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
echo json_encode(['ok' => false, 'error' => 'Invalid id']);
|
||||
exit;
|
||||
}
|
||||
$path = SCRIPTS_DIR . '/' . $id;
|
||||
$path = CUSTOM_SCRIPTS_DIR . '/' . substr($id, strlen('Custom/'));
|
||||
echo json_encode(['ok' => true, 'content' => file_exists($path) ? file_get_contents($path) : '']);
|
||||
exit;
|
||||
}
|
||||
@@ -24,7 +24,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
|
||||
$id = 'Custom/' . $name . '.sh';
|
||||
$path = SCRIPTS_DIR . '/Custom/' . $name . '.sh';
|
||||
$path = CUSTOM_SCRIPTS_DIR . '/' . $name . '.sh';
|
||||
|
||||
if ($action === 'delete') {
|
||||
if (!file_exists($path)) {
|
||||
@@ -40,7 +40,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
exit;
|
||||
}
|
||||
|
||||
$dir = SCRIPTS_DIR . '/Custom';
|
||||
$dir = CUSTOM_SCRIPTS_DIR;
|
||||
if (!is_dir($dir)) mkdir($dir, 0755, true);
|
||||
if (file_put_contents($path, $content) === false) {
|
||||
echo json_encode(['ok' => false, 'error' => 'Failed to write script']);
|
||||
|
||||
Reference in New Issue
Block a user