feat(cloudron): add tirreno package artifacts

- Add CloudronStack/output/CloudronPackages-Artifacts/tirreno/ directory and its contents
- Includes package manifest, Dockerfile, source code, documentation, and build artifacts
- Add tirreno-1761840148.tar.gz as a build artifact
- Add tirreno-cloudron-package-1761841304.tar.gz as the Cloudron package
- Include all necessary files for the tirreno Cloudron package

This adds the complete tirreno Cloudron package artifacts to the repository.
This commit is contained in:
2025-10-30 11:43:06 -05:00
parent 0ce353ea9d
commit 91d52d2de5
1692 changed files with 202851 additions and 0 deletions

View File

@@ -0,0 +1,397 @@
<?php
const MIN_PHP_VERSION = '8.0.0';
const MIN_MEMORY_LIM = 128 * 1024 * 1024;
$logo = (
' 888
888 888
888
88888888 888 888.d88 888.d88 .d88b. 88.d8b. .d88b.
888 888 888P" 888P" d8P Y8b 888 "88b d88""88b
888 888 888 888 88888888 888 888 888 888
888 888 888 888 Y8b .qq 888 888 888 888
888 888 888 888 d8bddr 888 888 R88 88P');
$style = (
'<style>
body {
background-color: #2b2a3d;
color: #d7e6e1;
font-family: monospace, monospace;
padding: 50px;
font-size: 13px;
}
input[type="text"],input[type="email"]{
width: 550px;
background-color: #151220;
color: #d7e6e1;
font-size: 100%;
}
label {
text-align: right;
display: block;
}
a {
color: #6e9fff;
}
</style>');
$installerHead = '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Installer</title>' . $style . '<head>';
$okTile = '[ <span style="color: #01ee99;">OK</span> ]';
$failTile = '[ <span style="color: #fb6e88;">FAIL</span> ]';
$nullTile = '[ -- ]';
$backButton = '<input action="action" onclick="window.history.go(-1); return false;" type="submit" value="Try again"/>';
$formBody = (
'<body>
<h3>Database connection details</h3>
<form action="/install/index.php" method="post">
<table width="688" cellpadding="5" cellspacing="0" border="0">
<tr>
<td><label for="db_user">Username</label></td>
<td><input type="text" id="db-user" name="db_user" autocomplete="off" autocapitalize="off" required></td>
</tr>
<tr>
<td><label for="db_pass">Password</label></td>
<td><input type="text" id="db-pass" name="db_pass" autocomplete="off" autocapitalize="off" required></td>
</tr>
<tr>
<td><label for="db_host">Host</label></td>
<td><input type="text" id="db-host" name="db_host" autocomplete="off" autocapitalize="off" required></td>
</tr>
<tr>
<td><label for="db_port">Port</label></td>
<td><input type="text" id="db-port" name="db_port" autocomplete="off" autocapitalize="off" required></td>
</tr>
<tr>
<td><label for="db_name">Database name</label></td>
<td><input type="text" id="db-name" name="db_name" autocomplete="off" autocapitalize="off" required></td>
</tr>
<tr>
<td><label for="admin_email">Admin email</label></td>
<td><input type="email" id="admin-email" name="admin_email" autocomplete="off" autocapitalize="off"></td>
</tr>
<tr>
<td colspan="2">
<hr>
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input type="submit" value="Connect"></td>
</tr>
</table>
</form>
</body>');
function resultHtmlStart() {
global $installerHead, $logo;
return $installerHead . '<body><pre>' . $logo;
}
function resultHtmlEnd() {
return '</pre></body></html>';
}
function formHtml() {
global $installerHead, $formBody;
return $installerHead . $formBody . '</html>';
}
function finishOk() {
$out = "\n\n======================== Setup completed! ========================";
$out .= "\n* Please delete the ./install directory and all its included files.";
$out .= "\n* Visit <a href=\"/signup\">/signup</a> to create your account.";
return $out;
}
function finishError() {
global $backButton;
$out = "\n====================== Something went wrong ======================";
$out .= "\n$backButton";
return $out;
}
$steps = [
[
'description' => 'Compatibility checks',
'tasks' => [
['description' => 'PHP version', 'status' => null],
['description' => 'PDO PostgreSQL driver', 'status' => null],
['description' => 'Configuration folder (/config) read/write permission', 'status' => null],
['description' => '.htaccess available', 'status' => null],
['description' => 'cURL', 'status' => null],
['description' => 'Memory limit (Min. 128MB)', 'status' => null],
],
],
[
'description' => 'Database params',
'tasks' => [
['description' => 'Schema accessible', 'status' => null],
['description' => 'Database name', 'status' => null],
['description' => 'Database user', 'status' => null],
['description' => 'Database password', 'status' => null],
['description' => 'Database host', 'status' => null],
['description' => 'Database port', 'status' => null],
],
],
[
'description' => 'Database setup',
'tasks' => [
['description' => 'Database connection', 'status' => null],
/*['description' => 'Database version', 'status' => null],*/
['description' => 'Apply database schema', 'status' => null],
],
],
[
'description' => 'Config build',
'tasks' => [
['description' => 'Write config file', 'status' => null],
],
],
];
function proceed() {
$out = '';
if (configAlreadyExists()) {
$out .= resultHtmlStart();
$out .= "\nThe app is already configured.";
$out .= resultHtmlEnd();
echo $out;
return;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$out .= resultHtmlStart();
[$status, $result, $config] = execute($_POST);
$out .= $result;
$out .= $status ? finishOk() : finishError();
$out .= resultHtmlEnd();
} else {
substituteFormWithEnv();
$out .= formHtml();
}
echo $out;
}
function execute(array $values) {
global $steps;
$out = '';
compatibilityCheck(0, $steps);
$out .= printTasks($steps[0]);
if (!tasksCompleted($steps[0])) {
return [false, $out, null];
}
dbConfig(1, $values, $steps);
$out .= printTasks($steps[1]);
if (!tasksCompleted($steps[1])) {
return [false, $out, null];
}
dbSaveConfig(2, $values, $steps);
$out .= printTasks($steps[2]);
if (!tasksCompleted($steps[2])) {
return [false, $out, null];
}
if (strval($values['mode'] ?? '') !== 'schema') {
$config = saveConfig(3, $values, $steps);
$out .= printTasks($steps[3]);
if (!tasksCompleted($steps[3])) {
return [false, $out, null];
}
}
return [true, $out, $config];
}
function configAlreadyExists(): bool {
return (getenv('SITE') && getenv('DATABASE_URL')) || file_exists('../config/local/config.local.ini');
}
function substituteFormWithEnv(): void {
global $formBody;
if (strval($_GET['mode'] ?? '') === 'schema') {
$formBody = preg_replace(
'/(<form\b[^>]*>)/i',
'$1<input type="hidden" name="mode" value="schema">',
$formBody
);
}
$dbUrl = getenv('DATABASE_URL');
if ($dbUrl) {
$parts = parse_url($dbUrl);
if ($parts) {
$values = [
'db_user' => $parts['user'] ?? '',
'db_pass' => $parts['pass'] ?? '',
'db_host' => $parts['host'] ?? '',
'db_port' => $parts['port'] ?? '',
'db_name' => trim(($parts['path'] ?? ''), '/'),
];
foreach ($values as $key => $value) {
$safe = htmlspecialchars($value, ENT_QUOTES|ENT_SUBSTITUTE, 'UTF-8');
$formBody = preg_replace(
'/(<input\b[^>]*\bname="' . preg_quote($key, '/') . '"(?![^>]*\bvalue=)[^>]*)(>)/i',
'$1 value="' . $safe . '"$2',
$formBody
);
}
}
}
}
function compatibilityCheck(int $step, array &$steps) {
$steps[$step]['tasks'][0]['status'] = version_compare(PHP_VERSION, MIN_PHP_VERSION) >= 0;
$steps[$step]['tasks'][1]['status'] = extension_loaded('pdo_pgsql') && extension_loaded('pgsql');
try {
if (is_writable('../config')) {
$f = fopen('../config/local/config.local.ini', 'w');
fclose($f);
unlink('../config/local/config.local.ini');
$steps[$step]['tasks'][2]['status'] = true;
} else {
$steps[$step]['tasks'][2]['status'] = false;
}
} catch (\Exception $e) {
$steps[$step]['tasks'][2]['status'] = false;
}
$steps[$step]['tasks'][3]['status'] = is_file('../.htaccess') && is_readable('../.htaccess');
$steps[$step]['tasks'][4]['status'] = extension_loaded('curl');
$memoryLimit = @ini_get('memory_limit');
$memLim = $memoryLimit;
preg_match('#^(\d+)(\w+)$#', strtolower($memLim), $match);
$memLim = match ($match[2]) {
'g' => intval($memLim) * 1024 * 1024 * 1024,
'm' => intval($memLim) * 1024 * 1024,
'k' => intval($memLim) * 1024,
default => intval($memLim),
};
$steps[$step]['tasks'][5]['status'] = $memLim >= MIN_MEMORY_LIM;
}
function dbConfig(int $step, array &$values, array &$steps) {
$steps[$step]['tasks'][0]['status'] = is_file('./install.sql');
$steps[$step]['tasks'][1]['status'] = $values['db_name'] !== '';
$steps[$step]['tasks'][2]['status'] = $values['db_user'] !== '';
$steps[$step]['tasks'][3]['status'] = $values['db_pass'] !== '';
$steps[$step]['tasks'][4]['status'] = $values['db_host'] !== '';
$steps[$step]['tasks'][5]['status'] = $values['db_port'] !== '';
}
function saveConfig(int $step, array $values, array &$steps): ?array {
$configData = null;
try {
$httpHost = strtolower(filter_var($_SERVER['HTTP_HOST'], FILTER_SANITIZE_URL));
if (strpos($httpHost, 'www.') === 0) {
$httpHost = substr($httpHost, 4);
} elseif (substr_count($httpHost, '.') == 1) {
$httpHost = 'www.' . $httpHost;
}
$httpHost = explode(':', $httpHost)[0];
$configData = [
'SITE' => $httpHost,
'DATABASE_URL' => "postgres://$values[db_user]:$values[db_pass]@$values[db_host]:$values[db_port]/$values[db_name]",
'PEPPER' => strval(bin2hex(random_bytes(32))),
];
if ($values['admin_email'] !== '') {
$configData['ADMIN_EMAIL'] = $values['admin_email'];
}
$config = "\n[globals]";
foreach ($configData as $key => $value) {
$config .= "\n$key=$value";
}
$configPath = '../config/local/config.local.ini';
$configFile = fopen($configPath, 'w');
fwrite($configFile, $config);
fclose($configFile);
$steps[$step]['tasks'][0]['status'] = true;
} catch (\Exception $e) {
$steps[$step]['tasks'][0]['status'] = false;
$steps[$step]['tasks'][0]['error'] = $e->getMessage();
}
return $configData;
}
function dbSaveConfig(int $step, array $values, array &$steps) {
$database = null;
$dsn = "pgsql:dbname=$values[db_name];host=$values[db_host];port=$values[db_port]";
$driverOptions = array(
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
);
try {
$database = new \PDO($dsn, $values['db_user'], $values['db_pass'], $driverOptions);
} catch (\Exception $e) {
$steps[$step]['tasks'][0]['status'] = false;
$steps[$step]['tasks'][0]['error'] = $e->getMessage();
return;
}
$steps[$step]['tasks'][0]['status'] = true;
/*$query = $database->query('SELECT VERSION()');
[$dbVersion] = $query->fetch(\PDO::FETCH_NUM);
if (!preg_match('/PostgreSQL (\d+\.\d+)/', $dbVersion, $matches) || version_compare($matches[1], '12.0', '<')) {
$steps[$step]['tasks'][1]['status'] = false;
return;
}
$steps[$step]['tasks'][1]['status'] = true;*/
try {
$sql = file_get_contents('./install.sql');
$database->exec($sql);
} catch (\Exception $e) {
$steps[$step]['tasks'][1]['status'] = false;
$steps[$step]['tasks'][1]['error'] = $e->getMessage();
return;
}
$steps[$step]['tasks'][1]['status'] = true;
}
function printTasks(array $tasks) {
global $okTile, $failTile, $nullTile;
$out = '';
$side = intdiv(64 - strlen($tasks['description']), 2);
$header = str_repeat('=', $side) . ' ' . $tasks['description'] . ' ' . str_repeat('=', $side);
$out .= "\n\n" . $header;
foreach ($tasks['tasks'] as $task) {
$st = ($task['status'] === true) ? $okTile : (($task['status'] === false) ? $failTile : $nullTile);
$err = array_key_exists('error', $task) ? ' (' . $task['error'] . ')' : '';
$out .= "\n" . $st . ' ' . $task['description'] . $err;
}
return $out;
}
function tasksCompleted(array $tasks) {
$results = array_column($tasks['tasks'], 'status');
return count(array_filter($results)) === count($results);
}
proceed();

File diff suppressed because it is too large Load Diff