mirror of
https://github.com/maxpozdeev/mytinytodo.git
synced 2026-03-11 08:55:27 +00:00
+ add updater extension
This commit is contained in:
parent
d36bab9e16
commit
56fa0fa039
6 changed files with 294 additions and 0 deletions
1
src/ext/updater/.htaccess
Normal file
1
src/ext/updater/.htaccess
Normal file
|
|
@ -0,0 +1 @@
|
|||
deny from all
|
||||
66
src/ext/updater/class.controller.php
Normal file
66
src/ext/updater/class.controller.php
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
This file is a part of myTinyTodo.
|
||||
(C) Copyright 2022 Max Pozdeev <maxpozdeev@gmail.com>
|
||||
Licensed under the GNU GPL version 2 or any later. See file COPYRIGHT for details.
|
||||
*/
|
||||
|
||||
namespace UpdaterExtension;
|
||||
|
||||
use \UpdaterExtension;
|
||||
use \Config;
|
||||
|
||||
class Controller extends \ApiController
|
||||
{
|
||||
function postCheck()
|
||||
{
|
||||
$prefs = UpdaterExtension::preferences();
|
||||
$a = UpdaterExtension::lastVersionInfo();
|
||||
if ($a) {
|
||||
$prefs['lastCheck'] = time();
|
||||
$prefs['version'] = $a['version'] ?? '';
|
||||
$prefs['download'] = $a['download'] ?? '';
|
||||
Config::saveDomain(UpdaterExtension::domain, $prefs);
|
||||
}
|
||||
$this->response->data = [ 'total' => 1 ];
|
||||
}
|
||||
|
||||
function postUpdate()
|
||||
{
|
||||
$prefs = UpdaterExtension::preferences();
|
||||
$url = $prefs['download'] ?? '';
|
||||
if ($url == '') {
|
||||
$this->response->data = [ 'total' => 0, 'msg' => __("updater.download_error") ];
|
||||
return;
|
||||
}
|
||||
$file = MTTPATH. 'update.tar.gz';
|
||||
$error = null;
|
||||
if (!UpdaterExtension::download($url, $file, $error)) {
|
||||
$this->response->data = [ 'total' => 0, 'msg' => __("updater.download_error"), 'details' => $error ];
|
||||
return;
|
||||
}
|
||||
$error = null;
|
||||
if (!UpdaterExtension::extractAndReplace($file, $error)) {
|
||||
$this->response->data = [ 'total' => 0, 'msg' => __("updater.update_error"), 'details' => $error ];
|
||||
return;
|
||||
}
|
||||
@unlink($file);
|
||||
|
||||
if (function_exists("opcache_reset")) {
|
||||
opcache_reset();
|
||||
}
|
||||
|
||||
// TODO: need to run post-update by new version
|
||||
// ...
|
||||
|
||||
$prefs['version'] = '';
|
||||
$prefs['download'] = '';
|
||||
$prefs['lastCheck'] = 0;
|
||||
Config::saveDomain(UpdaterExtension::domain, $prefs);
|
||||
|
||||
$this->response->data = [ 'total' => 1, 'msg' => __("updater.updated"), 'reload' => 'ext-settings' ];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
6
src/ext/updater/extension.json
Normal file
6
src/ext/updater/extension.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"bundleId": "updater",
|
||||
"name": "Updates",
|
||||
"version": "0.9",
|
||||
"description": "myTinyTodo self-updater"
|
||||
}
|
||||
13
src/ext/updater/lang/en.json
Normal file
13
src/ext/updater/lang/en.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"ext.updater.name": "Updates",
|
||||
"updater.h_check_updates": "Check updates",
|
||||
"updater.check": "Check",
|
||||
"updater.no_updates": "No updates available",
|
||||
"updater.current_version": "Current version",
|
||||
"updater.last_checked": "Last checked",
|
||||
"updater.updatet_version_avaialable": "Updated version is available",
|
||||
"updater.update": "Update",
|
||||
"updater.updated": "Update has completed",
|
||||
"updater.download_error": "Download failed",
|
||||
"updater.update_error": "Update error"
|
||||
}
|
||||
13
src/ext/updater/lang/ru.json
Normal file
13
src/ext/updater/lang/ru.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"ext.updater.name": "Обновления",
|
||||
"updater.h_check_updates": "Проверка обновлений",
|
||||
"updater.check": "Проверить",
|
||||
"updater.no_updates": "Нет обновлений",
|
||||
"updater.current_version": "Текущая версия",
|
||||
"updater.last_checked": "Последняя проверка",
|
||||
"updater.updatet_version_avaialable": "Доступно обновление",
|
||||
"updater.update": "Обновить",
|
||||
"updater.updated": "Обновление завершено",
|
||||
"updater.download_error": "Ошибка при загрузке",
|
||||
"updater.update_error": "Ошибка при обновлении"
|
||||
}
|
||||
195
src/ext/updater/loader.php
Normal file
195
src/ext/updater/loader.php
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
/*
|
||||
This file is a part of myTinyTodo.
|
||||
(C) Copyright 2022 Max Pozdeev <maxpozdeev@gmail.com>
|
||||
Licensed under the GNU GPL version 2 or any later. See file COPYRIGHT for details.
|
||||
*/
|
||||
|
||||
if (!defined('MTTPATH')) {
|
||||
die("Unexpected usage.");
|
||||
}
|
||||
|
||||
require_once('class.controller.php');
|
||||
|
||||
function mtt_ext_updater_instance(): MTTExtension
|
||||
{
|
||||
return new UpdaterExtension();
|
||||
}
|
||||
|
||||
use UpdaterExtension\Controller;
|
||||
|
||||
class UpdaterExtension extends MTTExtension implements MTTExtensionSettingsInterface, MTTHttpApiExtender
|
||||
{
|
||||
//the same as dir name
|
||||
const bundleId = 'updater';
|
||||
|
||||
// settings domain
|
||||
const domain = "ext.updater.json";
|
||||
|
||||
function init()
|
||||
{
|
||||
}
|
||||
|
||||
// MTTHttpApiExtender
|
||||
function extendHttpApi(): array
|
||||
{
|
||||
return array(
|
||||
'/check' => [
|
||||
'POST' => [ Controller::class , 'postCheck' ],
|
||||
],
|
||||
'/update' => [
|
||||
'POST' => [ Controller::class , 'postUpdate' ],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
function settingsPage(): string
|
||||
{
|
||||
$e = function($s) { return __($s, true); };
|
||||
$ext = htmlspecialchars(self::bundleId);
|
||||
$prefs = self::preferences();
|
||||
$lastCheck = $prefs['lastCheck'] ?? 0;
|
||||
$version = $prefs['version'] ?? '';
|
||||
$updateStr = '';
|
||||
$curVersion = htmlspecialchars(mytinytodo\Version::VERSION);
|
||||
if (time() - $lastCheck > 86400*7) {
|
||||
$a = self::lastVersionInfo();
|
||||
if ($a) {
|
||||
$lastCheck = $prefs['lastCheck'] = time();
|
||||
$version = $prefs['version'] = $a['version'] ?? '';
|
||||
$prefs['download'] = $a['download'] ?? '';
|
||||
Config::saveDomain(self::domain, $prefs);
|
||||
}
|
||||
}
|
||||
if ($version != '') {
|
||||
if ( version_compare($version, mytinytodo\Version::VERSION) > 0 ) {
|
||||
$updateStr = "<br> {$e('updater.updatet_version_avaialable')}: ". htmlspecialchars($version);
|
||||
if ("1.7." == substr($version, 0, 4)) {
|
||||
$updateStr .= "<br><br>\n <a href=\"#\" data-ext-settings-action=\"post:update\" data-ext=\"$ext\">{$e('updater.update')}</a> ";
|
||||
}
|
||||
}
|
||||
else {
|
||||
$updateStr = "<br>{$e('updater.no_updates')}";
|
||||
}
|
||||
}
|
||||
$lastCheckStr = $lastCheck ? timestampToDatetime($lastCheck, true) : "";
|
||||
|
||||
|
||||
return
|
||||
<<<EOD
|
||||
<div class="tr">
|
||||
<div class="th"> {$e('updater.h_check_updates')} </div>
|
||||
<div class="td">
|
||||
{$e('updater.current_version')}: $curVersion <br>
|
||||
{$e('updater.last_checked')}: $lastCheckStr <button type=button data-ext-settings-action="post:check" data-ext="$ext">{$e('updater.check')}</button> <br>
|
||||
$updateStr
|
||||
</div>
|
||||
</div>
|
||||
EOD;
|
||||
}
|
||||
|
||||
function saveSettings(array $params, ?string &$outMessage): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static function preferences(): array
|
||||
{
|
||||
$prefs = Config::requestDomain(self::domain);
|
||||
return $prefs;
|
||||
}
|
||||
|
||||
static function lastVersionInfo(): ?array
|
||||
{
|
||||
$options = array(
|
||||
'http' => array(
|
||||
'header' => "Content-type: application/json\r\nUser-Agent: mytinytodo\r\n"
|
||||
)
|
||||
);
|
||||
$context = stream_context_create($options);
|
||||
$json = @file_get_contents("https://api.github.com/repos/maxpozdeev/mytinytodo/releases/latest", false, $context);
|
||||
if ($json === false || $json == '') {
|
||||
return null;
|
||||
}
|
||||
$a = json_decode($json, true) ?? [];
|
||||
$ret = [];
|
||||
if ( isset($a['name']) && isset($a['assets']) &&
|
||||
is_array($a['assets']) && count($a['assets']) > 0 &&
|
||||
($asset = $a['assets'][0]) && isset($asset['browser_download_url']) )
|
||||
{
|
||||
$ret['version'] = substr($a['name'], 1); //remove first 'v'
|
||||
$ret['download'] = $asset['browser_download_url'];
|
||||
}
|
||||
else {
|
||||
error_log("Unexpected content");
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
static function download(string $url, string $outfile, string &$error = null): bool
|
||||
{
|
||||
$dir = dirname($outfile);
|
||||
if (!is_dir($dir) || !is_writable($dir)) {
|
||||
$error = "myTinyTodo directory is not writable";
|
||||
return false;
|
||||
}
|
||||
$f = @fopen($url, 'r');
|
||||
if ($f === false) {
|
||||
$ea = error_get_last();
|
||||
$error = ($ea && isset($ea['message'])) ? $ea['message'] : "Failed to open stream";
|
||||
return false;
|
||||
}
|
||||
$bytes = @file_put_contents($outfile, $f, LOCK_EX);
|
||||
$ea = error_get_last();
|
||||
fclose($f);
|
||||
if ($bytes === false) {
|
||||
$error = ($ea && isset($ea['message'])) ? $ea['message'] : "Can not save file";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static function extractAndReplace(string $filename, string &$error = null): bool
|
||||
{
|
||||
$dir = MTTPATH;
|
||||
if (!is_dir($dir) || !is_writable($dir)) {
|
||||
$error = "myTinyTodo directory is not writable";
|
||||
return false;
|
||||
}
|
||||
|
||||
$output = null;
|
||||
$retval = null;
|
||||
$command = "tar xzf ". escapeshellarg($filename). " --strip-components 1 -C ". escapeshellarg($dir). " 2>&1";
|
||||
@exec($command, $output, $retval);
|
||||
if ($retval != 0) {
|
||||
$error = "Failed to execute tar command ($retval): ". ($output ? implode("\n", $output) : "no output");
|
||||
error_log($error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extensions
|
||||
$dir = MTT_EXT;
|
||||
$filename = $dir . 'extensions.tar.gz';
|
||||
if (file_exists($filename)) {
|
||||
if (!is_writable($dir)) {
|
||||
$error = "Extensions directory is not writable";
|
||||
return false;
|
||||
}
|
||||
$command = "tar xzf ". escapeshellarg($filename). " -C ". escapeshellarg($dir). " 2>&1";
|
||||
@exec($command, $output, $retval);
|
||||
if ($retval != 0) {
|
||||
$error = "Extensions: failed to execute tar command ($retval): ". ($output ? implode("\n", $output) : "no output");
|
||||
error_log($error);
|
||||
return false;
|
||||
}
|
||||
unlink($filename);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue