mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-29 03:59:21 +03:00
Move admin repository handling code to \SnappyMail\Repository
This commit is contained in:
parent
c5fc3d24a9
commit
3251611c6d
2 changed files with 262 additions and 231 deletions
|
|
@ -466,222 +466,6 @@ trait Admin
|
|||
));
|
||||
}
|
||||
|
||||
private function snappyMailRepo() : string
|
||||
{
|
||||
return 'https://snappymail.eu/repository/v2/';
|
||||
}
|
||||
|
||||
private function getRepositoryDataByUrl(bool &$bReal = false) : array
|
||||
{
|
||||
$bReal = false;
|
||||
$aRep = null;
|
||||
|
||||
$sRep = '';
|
||||
$sRepoFile = 'packages.json';
|
||||
$iRepTime = 0;
|
||||
|
||||
$sCacheKey = KeyPathHelper::RepositoryCacheFile(\SnappyMail\Repository::BASE_URL, $sRepoFile);
|
||||
$sRep = $this->Cacher()->Get($sCacheKey);
|
||||
if ('' !== $sRep)
|
||||
{
|
||||
$iRepTime = $this->Cacher()->GetTimer($sCacheKey);
|
||||
}
|
||||
|
||||
if ('' === $sRep || 0 === $iRepTime || \time() - 3600 > $iRepTime)
|
||||
{
|
||||
$sRep = \SnappyMail\Repository::get($sRepoFile,
|
||||
$this->Config()->Get('labs', 'curl_proxy', ''),
|
||||
$this->Config()->Get('labs', 'curl_proxy_auth', '')
|
||||
);
|
||||
if ($sRep)
|
||||
{
|
||||
$aRep = \json_decode($sRep);
|
||||
$bReal = \is_array($aRep) && \count($aRep);
|
||||
|
||||
if ($bReal)
|
||||
{
|
||||
$this->Cacher()->Set($sCacheKey, $sRep);
|
||||
$this->Cacher()->SetTimer($sCacheKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception('Cannot read remote repository file: '.$sRepoFile);
|
||||
}
|
||||
}
|
||||
else if ('' !== $sRep)
|
||||
{
|
||||
$aRep = \json_decode($sRep, false, 10);
|
||||
$bReal = \is_array($aRep) && \count($aRep);
|
||||
}
|
||||
|
||||
return \is_array($aRep) ? $aRep : [];
|
||||
}
|
||||
|
||||
private function getRepositoryData(bool &$bReal, string &$sError) : array
|
||||
{
|
||||
$aResult = array();
|
||||
try {
|
||||
$notDev = '0.0.0' !== APP_VERSION;
|
||||
foreach ($this->getRepositoryDataByUrl($bReal) as $oItem) {
|
||||
if ($oItem && isset($oItem->type, $oItem->id, $oItem->name,
|
||||
$oItem->version, $oItem->release, $oItem->file, $oItem->description))
|
||||
{
|
||||
if (!empty($oItem->required) && $notDev && \version_compare(APP_VERSION, $oItem->required, '<')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!empty($oItem->depricated) && $notDev && \version_compare(APP_VERSION, $oItem->depricated, '>=')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('plugin' === $oItem->type) {
|
||||
$aResult[$oItem->id] = array(
|
||||
'type' => $oItem->type,
|
||||
'id' => $oItem->id,
|
||||
'name' => $oItem->name,
|
||||
'installed' => '',
|
||||
'enabled' => true,
|
||||
'version' => $oItem->version,
|
||||
'file' => $oItem->file,
|
||||
'release' => $oItem->release,
|
||||
'desc' => $oItem->description,
|
||||
'canBeDeleted' => false,
|
||||
'canBeUpdated' => true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$sError = "{$e->getCode()} {$e->getMessage()}";
|
||||
$this->Logger()->Write($sError, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
public function DoAdminPackagesList() : array
|
||||
{
|
||||
$this->IsAdminLoggined();
|
||||
|
||||
$bReal = false;
|
||||
$sError = '';
|
||||
$aList = $this->getRepositoryData($bReal, $sError);
|
||||
|
||||
$aEnabledPlugins = \array_map('trim',
|
||||
\explode(',', \strtolower($this->Config()->Get('plugins', 'enabled_list', '')))
|
||||
);
|
||||
|
||||
$aInstalled = $this->Plugins()->InstalledPlugins();
|
||||
foreach ($aInstalled as $aItem) {
|
||||
if ($aItem) {
|
||||
if (isset($aList[$aItem[0]])) {
|
||||
$aList[$aItem[0]]['installed'] = $aItem[1];
|
||||
$aList[$aItem[0]]['enabled'] = \in_array(\strtolower($aItem[0]), $aEnabledPlugins);
|
||||
$aList[$aItem[0]]['canBeDeleted'] = true;
|
||||
$aList[$aItem[0]]['canBeUpdated'] = \version_compare($aItem[1], $aList[$aItem[0]]['version'], '<');
|
||||
} else {
|
||||
\array_push($aList, array(
|
||||
'type' => 'plugin',
|
||||
'id' => $aItem[0],
|
||||
'name' => $aItem[0],
|
||||
'installed' => $aItem[1],
|
||||
'enabled' => \in_array(\strtolower($aItem[0]), $aEnabledPlugins),
|
||||
'version' => '',
|
||||
'file' => '',
|
||||
'release' => '',
|
||||
'desc' => '',
|
||||
'canBeDeleted' => true,
|
||||
'canBeUpdated' => false
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// \uksort($aList, function($a, $b){return \strcasecmp($a['name'], $b['name']);});
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__, array(
|
||||
'Real' => $bReal,
|
||||
'List' => \array_values($aList),
|
||||
'Error' => $sError
|
||||
));
|
||||
}
|
||||
|
||||
public function DoAdminPackageDelete() : array
|
||||
{
|
||||
$this->IsAdminLoggined();
|
||||
|
||||
$sId = $this->GetActionParam('Id', '');
|
||||
|
||||
$bResult = static::deletePackageDir($sId);
|
||||
$this->pluginEnable($sId, false);
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__, $bResult);
|
||||
}
|
||||
|
||||
private static function deletePackageDir(string $sId) : bool
|
||||
{
|
||||
$sPath = APP_PLUGINS_PATH.$sId;
|
||||
return (!\is_dir($sPath) || \MailSo\Base\Utils::RecRmDir($sPath))
|
||||
&& (!\is_file("{$sPath}.phar") || \unlink("{$sPath}.phar"));
|
||||
}
|
||||
|
||||
public function DoAdminPackageInstall() : array
|
||||
{
|
||||
$this->IsAdminLoggined();
|
||||
|
||||
$sType = $this->GetActionParam('Type', '');
|
||||
$sId = $this->GetActionParam('Id', '');
|
||||
$sFile = $this->GetActionParam('File', '');
|
||||
|
||||
$this->Logger()->Write('Start package install: '.$sFile.' ('.$sType.')', \MailSo\Log\Enumerations\Type::INFO, 'INSTALLER');
|
||||
|
||||
$sRealFile = '';
|
||||
|
||||
$bResult = false;
|
||||
$sTmp = null;
|
||||
try {
|
||||
if ('plugin' === $sType) {
|
||||
$bReal = false;
|
||||
$sError = '';
|
||||
$aList = $this->getRepositoryData($bReal, $sError);
|
||||
if ($sError) {
|
||||
throw new \Exception($sError);
|
||||
}
|
||||
if (isset($aList[$sId]) && $sFile === $aList[$sId]['file']) {
|
||||
$sRealFile = $sFile;
|
||||
$sTmp = \SnappyMail\Repository::download($sFile,
|
||||
$this->Config()->Get('labs', 'curl_proxy', ''),
|
||||
$this->Config()->Get('labs', 'curl_proxy_auth', '')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($sTmp) {
|
||||
$oArchive = new \PharData($sTmp, 0, $sRealFile);
|
||||
if (static::deletePackageDir($sId)) {
|
||||
if ('.phar' === \substr($sRealFile, -5)) {
|
||||
$bResult = \copy($sTmp, APP_PLUGINS_PATH . \basename($sRealFile));
|
||||
} else {
|
||||
$bResult = $oArchive->extractTo(\rtrim(APP_PLUGINS_PATH, '\\/'));
|
||||
}
|
||||
if (!$bResult) {
|
||||
throw new \Exception('Cannot extract package files: '.$oArchive->getStatusString());
|
||||
}
|
||||
} else {
|
||||
throw new \Exception('Cannot remove previous plugin folder: '.$sId);
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$this->Logger()->Write("Install package {$sRealFile} failed: {$e->getMessage()}", \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
|
||||
throw $e;
|
||||
} finally {
|
||||
$sTmp && \unlink($sTmp);
|
||||
}
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__, $bResult ?
|
||||
('plugin' !== $sType ? array('Reload' => true) : true) : false);
|
||||
}
|
||||
|
||||
public function DoAdminPHPExtensions() : array
|
||||
{
|
||||
$aResult = [
|
||||
|
|
@ -699,6 +483,31 @@ trait Admin
|
|||
return $this->DefaultResponse(__FUNCTION__, $aResult);
|
||||
}
|
||||
|
||||
public function DoAdminPackagesList() : array
|
||||
{
|
||||
return $this->DefaultResponse(__FUNCTION__, \SnappyMail\Repository::getPackagesList());
|
||||
}
|
||||
|
||||
public function DoAdminPackageDelete() : array
|
||||
{
|
||||
$sId = $this->GetActionParam('Id', '');
|
||||
$bResult = \SnappyMail\Repository::deletePackage($sId);
|
||||
static::pluginEnable($sId, false);
|
||||
return $this->DefaultResponse(__FUNCTION__, $bResult);
|
||||
}
|
||||
|
||||
public function DoAdminPackageInstall() : array
|
||||
{
|
||||
$sType = $this->GetActionParam('Type', '');
|
||||
$bResult = \SnappyMail\Repository::installPackage(
|
||||
$sType,
|
||||
$this->GetActionParam('Id', ''),
|
||||
$this->GetActionParam('File', '')
|
||||
);
|
||||
return $this->DefaultResponse(__FUNCTION__, $bResult ?
|
||||
('plugin' !== $sType ? array('Reload' => true) : true) : false);
|
||||
}
|
||||
|
||||
private function pluginEnable(string $sName, bool $bEnable = true) : bool
|
||||
{
|
||||
if (!\strlen($sName))
|
||||
|
|
@ -877,19 +686,6 @@ trait Admin
|
|||
return $this->DefaultResponse(__FUNCTION__, true);
|
||||
}
|
||||
|
||||
private function HasOneOfActionParams(array $aKeys) : bool
|
||||
{
|
||||
foreach ($aKeys as $sKey)
|
||||
{
|
||||
if ($this->HasActionParam($sKey))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function setConfigFromParams(\RainLoop\Config\Application $oConfig, string $sParamName, string $sConfigSector, string $sConfigName, string $sType = 'string', ?callable $mStringCallback = null): void
|
||||
{
|
||||
$sValue = $this->GetActionParam($sParamName, '');
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ abstract class Repository
|
|||
// snappyMailRepo
|
||||
const BASE_URL = 'https://snappymail.eu/repository/v2/';
|
||||
|
||||
public static function get(string $path, string $proxy, string $proxy_auth) : string
|
||||
private static function get(string $path, string $proxy, string $proxy_auth) : string
|
||||
{
|
||||
$oHTTP = HTTP\Request::factory(/*'socket' or 'curl'*/);
|
||||
$oHTTP->proxy = $proxy;
|
||||
|
|
@ -26,7 +26,7 @@ abstract class Repository
|
|||
|
||||
// $aRep = \json_decode($sRep);
|
||||
|
||||
public static function download(string $path, string $proxy, string $proxy_auth) : string
|
||||
private static function download(string $path, string $proxy, string $proxy_auth) : string
|
||||
{
|
||||
$sTmp = APP_PRIVATE_DATA . \md5(\microtime(true).$path) . \preg_replace('/^.*?(\\.[a-z\\.]+)$/Di', '$1', $path);
|
||||
$pDest = \fopen($sTmp, 'w+b');
|
||||
|
|
@ -61,4 +61,239 @@ abstract class Repository
|
|||
));
|
||||
}
|
||||
|
||||
private static function getRepositoryDataByUrl(bool &$bReal = false) : array
|
||||
{
|
||||
$bReal = false;
|
||||
$aRep = null;
|
||||
|
||||
$sRep = '';
|
||||
$sRepoFile = 'packages.json';
|
||||
$iRepTime = 0;
|
||||
|
||||
$oCache = \RainLoop\Api::Actions()->Cacher();
|
||||
|
||||
$sCacheKey = \RainLoop\KeyPathHelper::RepositoryCacheFile(static::BASE_URL, $sRepoFile);
|
||||
$sRep = $oCache->Get($sCacheKey);
|
||||
if ('' !== $sRep)
|
||||
{
|
||||
$iRepTime = $oCache->GetTimer($sCacheKey);
|
||||
}
|
||||
|
||||
if ('' === $sRep || 0 === $iRepTime || \time() - 3600 > $iRepTime)
|
||||
{
|
||||
$sRep = static::get($sRepoFile,
|
||||
\RainLoop\Api::Config()->Get('labs', 'curl_proxy', ''),
|
||||
\RainLoop\Api::Config()->Get('labs', 'curl_proxy_auth', '')
|
||||
);
|
||||
if ($sRep)
|
||||
{
|
||||
$aRep = \json_decode($sRep);
|
||||
$bReal = \is_array($aRep) && \count($aRep);
|
||||
|
||||
if ($bReal)
|
||||
{
|
||||
$oCache->Set($sCacheKey, $sRep);
|
||||
$oCache->SetTimer($sCacheKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception('Cannot read remote repository file: '.$sRepoFile);
|
||||
}
|
||||
}
|
||||
else if ('' !== $sRep)
|
||||
{
|
||||
$aRep = \json_decode($sRep, false, 10);
|
||||
$bReal = \is_array($aRep) && \count($aRep);
|
||||
}
|
||||
|
||||
return \is_array($aRep) ? $aRep : [];
|
||||
}
|
||||
|
||||
private static function getRepositoryData(bool &$bReal, string &$sError) : array
|
||||
{
|
||||
$aResult = array();
|
||||
try {
|
||||
$notDev = '0.0.0' !== APP_VERSION;
|
||||
foreach (static::getRepositoryDataByUrl($bReal) as $oItem) {
|
||||
if ($oItem && isset($oItem->type, $oItem->id, $oItem->name,
|
||||
$oItem->version, $oItem->release, $oItem->file, $oItem->description))
|
||||
{
|
||||
if ((!empty($oItem->required) && $notDev && \version_compare(APP_VERSION, $oItem->required, '<'))
|
||||
|| (!empty($oItem->deprecated) && $notDev && \version_compare(APP_VERSION, $oItem->deprecated, '>='))
|
||||
|| (isset($aResult[$oItem->id]) && \version_compare($aResult[$oItem->id]['version'], $oItem->version, '>'))
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ('plugin' === $oItem->type) {
|
||||
$aResult[$oItem->id] = array(
|
||||
'type' => $oItem->type,
|
||||
'id' => $oItem->id,
|
||||
'name' => $oItem->name,
|
||||
'installed' => '',
|
||||
'enabled' => true,
|
||||
'version' => $oItem->version,
|
||||
'file' => $oItem->file,
|
||||
'release' => $oItem->release,
|
||||
'desc' => $oItem->description,
|
||||
'canBeDeleted' => false,
|
||||
'canBeUpdated' => true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$sError = "{$e->getCode()} {$e->getMessage()}";
|
||||
\RainLoop\Api::Logger()->Write($sError, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
public static function getPackagesList() : array
|
||||
{
|
||||
\RainLoop\Api::Actions()->IsAdminLoggined();
|
||||
|
||||
$bReal = false;
|
||||
$sError = '';
|
||||
$aList = static::getRepositoryData($bReal, $sError);
|
||||
|
||||
$aEnabledPlugins = \array_map('trim',
|
||||
\explode(',', \strtolower(\RainLoop\Api::Config()->Get('plugins', 'enabled_list', '')))
|
||||
);
|
||||
|
||||
$aInstalled = \RainLoop\Api::Actions()->Plugins()->InstalledPlugins();
|
||||
foreach ($aInstalled as $aItem) {
|
||||
if ($aItem) {
|
||||
if (isset($aList[$aItem[0]])) {
|
||||
$aList[$aItem[0]]['installed'] = $aItem[1];
|
||||
$aList[$aItem[0]]['enabled'] = \in_array(\strtolower($aItem[0]), $aEnabledPlugins);
|
||||
$aList[$aItem[0]]['canBeDeleted'] = true;
|
||||
$aList[$aItem[0]]['canBeUpdated'] = \version_compare($aItem[1], $aList[$aItem[0]]['version'], '<');
|
||||
} else {
|
||||
\array_push($aList, array(
|
||||
'type' => 'plugin',
|
||||
'id' => $aItem[0],
|
||||
'name' => $aItem[0],
|
||||
'installed' => $aItem[1],
|
||||
'enabled' => \in_array(\strtolower($aItem[0]), $aEnabledPlugins),
|
||||
'version' => '',
|
||||
'file' => '',
|
||||
'release' => '',
|
||||
'desc' => '',
|
||||
'canBeDeleted' => true,
|
||||
'canBeUpdated' => false
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// \uksort($aList, static function($a, $b){return \strcasecmp($a['name'], $b['name']);});
|
||||
|
||||
return array(
|
||||
'Real' => $bReal,
|
||||
'List' => \array_values($aList),
|
||||
'Error' => $sError
|
||||
);
|
||||
}
|
||||
|
||||
public static function deletePackage(string $sId) : bool
|
||||
{
|
||||
\RainLoop\Api::Actions()->IsAdminLoggined();
|
||||
return static::deletePackageDir($sId);
|
||||
}
|
||||
|
||||
private static function deletePackageDir(string $sId) : bool
|
||||
{
|
||||
$sPath = APP_PLUGINS_PATH.$sId;
|
||||
return (!\is_dir($sPath) || \MailSo\Base\Utils::RecRmDir($sPath))
|
||||
&& (!\is_file("{$sPath}.phar") || \unlink("{$sPath}.phar"));
|
||||
}
|
||||
|
||||
public static function installPackage(string $sType, string $sId, string $sFile) : bool
|
||||
{
|
||||
\RainLoop\Api::Actions()->IsAdminLoggined();
|
||||
|
||||
\RainLoop\Api::Logger()->Write('Start package install: '.$sFile.' ('.$sType.')', \MailSo\Log\Enumerations\Type::INFO, 'INSTALLER');
|
||||
|
||||
$sRealFile = '';
|
||||
|
||||
$bResult = false;
|
||||
$sTmp = null;
|
||||
try {
|
||||
if ('plugin' === $sType) {
|
||||
$bReal = false;
|
||||
$sError = '';
|
||||
$aList = static::getRepositoryData($bReal, $sError);
|
||||
if ($sError) {
|
||||
throw new \Exception($sError);
|
||||
}
|
||||
if (isset($aList[$sId]) && $sFile === $aList[$sId]['file']) {
|
||||
$sRealFile = $sFile;
|
||||
$sTmp = static::download($sFile,
|
||||
\RainLoop\Api::Config()->Get('labs', 'curl_proxy', ''),
|
||||
\RainLoop\Api::Config()->Get('labs', 'curl_proxy_auth', '')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($sTmp) {
|
||||
$oArchive = new \PharData($sTmp, 0, $sRealFile);
|
||||
if (static::deletePackageDir($sId)) {
|
||||
if ('.phar' === \substr($sRealFile, -5)) {
|
||||
$bResult = \copy($sTmp, APP_PLUGINS_PATH . \basename($sRealFile));
|
||||
} else {
|
||||
$bResult = $oArchive->extractTo(\rtrim(APP_PLUGINS_PATH, '\\/'));
|
||||
}
|
||||
if (!$bResult) {
|
||||
throw new \Exception('Cannot extract package files: '.$oArchive->getStatusString());
|
||||
}
|
||||
} else {
|
||||
throw new \Exception('Cannot remove previous plugin folder: '.$sId);
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
\RainLoop\Api::Logger()->Write("Install package {$sRealFile} failed: {$e->getMessage()}", \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
|
||||
throw $e;
|
||||
} finally {
|
||||
$sTmp && \unlink($sTmp);
|
||||
}
|
||||
|
||||
return $bResult;
|
||||
}
|
||||
|
||||
private static function pluginEnable(string $sName, bool $bEnable = true) : bool
|
||||
{
|
||||
if (!\strlen($sName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$oConfig = \RainLoop\Api::Config();
|
||||
|
||||
$sEnabledPlugins = $oConfig->Get('plugins', 'enabled_list', '');
|
||||
$aEnabledPlugins = \explode(',', \strtolower($sEnabledPlugins));
|
||||
$aEnabledPlugins = \array_map('trim', $aEnabledPlugins);
|
||||
|
||||
$aNewEnabledPlugins = array();
|
||||
if ($bEnable)
|
||||
{
|
||||
$aNewEnabledPlugins = $aEnabledPlugins;
|
||||
$aNewEnabledPlugins[] = $sName;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($aEnabledPlugins as $sPlugin)
|
||||
{
|
||||
if ($sName !== $sPlugin && \strlen($sPlugin))
|
||||
{
|
||||
$aNewEnabledPlugins[] = $sPlugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oConfig->Set('plugins', 'enabled_list', \trim(\implode(',', \array_unique($aNewEnabledPlugins)), ' ,'));
|
||||
|
||||
return $oConfig->Save();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue