Release plugins as tar.gz because PharData is more common then ZipArchive

This commit is contained in:
djmaze 2021-02-10 09:50:20 +01:00
parent 756bf86640
commit b9b0a550d6
47 changed files with 214 additions and 159 deletions

View file

@ -1 +0,0 @@
1.2

View file

@ -2,6 +2,11 @@
class AddXOriginatingIpHeaderPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = 'X-Originating-IP',
VERSION = '2.0',
DESCRIPTION = 'Adds X-Originating-IP header to outgoing message, containing sender\'s IP address.';
public function Init() : void
{
$this->addHook('filter.build-message', 'FilterBuildMessage');

View file

@ -1 +0,0 @@
1.1

View file

@ -12,6 +12,10 @@
class AutoDomainGrabPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = '',
CATEGORY = 'General',
DESCRIPTION = '';
private $imap_prefix = "mail.";
private $smtp_prefix = "mail.";

View file

@ -1 +0,0 @@
1.0

View file

@ -2,6 +2,12 @@
class BlackListPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = 'Black list',
VERSION = '2.0',
CATEGORY = 'Login',
DESCRIPTION = 'Simple black list plugin (with wildcard and exceptions functionality).';
public function Init() : void
{
$this->addHook('filter.login-credentials', 'FilterLoginCredentials');

View file

@ -1 +0,0 @@
1.0

View file

@ -2,6 +2,11 @@
class ChangeSmtpEhloMessagePlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = '',
CATEGORY = 'General',
DESCRIPTION = '';
public function Init() : void
{
$this->addHook('filter.smtp-credentials', 'FilterSmtpCredentials');

View file

@ -1 +0,0 @@
0.1

View file

@ -2,6 +2,11 @@
class ContactGroupExcelPastePlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = '',
CATEGORY = 'General',
DESCRIPTION = '';
public function Init() : void
{
$this->addJs('js/excel_contact_group.js');

View file

@ -1 +0,0 @@
1.0

View file

@ -2,6 +2,11 @@
class ContactsSuggestionsExamplePlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = '',
CATEGORY = 'General',
DESCRIPTION = '';
public function Init() : void
{
$this->addHook('main.fabrica', 'MainFabrica');

View file

@ -1 +0,0 @@
1.0

View file

@ -2,6 +2,11 @@
class CustomAdminSettingsTabPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = '',
CATEGORY = 'General',
DESCRIPTION = '';
/**
* @return void
*/

View file

@ -1 +0,0 @@
1.0

View file

@ -2,6 +2,11 @@
class CustomAuthExamplePlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = '',
CATEGORY = 'Login',
DESCRIPTION = '';
public function Init() : void
{
$this->addHook('filter.login-credentials', 'FilterLoginСredentials');

View file

@ -1 +0,0 @@
1.0

View file

@ -2,6 +2,12 @@
class CustomLoginMappingPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = 'Custom Login Mapping',
VERSION = '2.0',
CATEGORY = 'Login',
DESCRIPTION = 'Plugin which allows you to set up custom username by email address.';
public function Init() : void
{
$this->addHook('filter.login-credentials', 'FilterLoginСredentials');

View file

@ -1 +0,0 @@
1.1

View file

@ -2,6 +2,11 @@
class CustomSettingsTabPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = '',
CATEGORY = 'General',
DESCRIPTION = '';
/**
* @return void
*/

View file

@ -1 +0,0 @@
1.0

View file

@ -2,6 +2,11 @@
class CustomSystemFoldersPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = '',
CATEGORY = 'General',
DESCRIPTION = '';
/**
* @var string
*/

View file

@ -1 +0,0 @@
1.0

View file

@ -2,6 +2,11 @@
class DemoAccountPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = '',
CATEGORY = 'Login',
DESCRIPTION = '';
/**
* @return void
*/

View file

@ -1,20 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013 https://github.com/sharq88
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1 +0,0 @@
Add ability to paste multi row email addresses from excel.

View file

@ -1 +0,0 @@
0.1

View file

@ -1,12 +0,0 @@
<?php
class ParseExcelListPlugin extends \RainLoop\Plugins\AbstractPlugin
{
/**
* @return void
*/
public function Init() : void
{
$this->addJs('js/parse_excel_list.js'); // add js file
}
}

View file

@ -1,22 +0,0 @@
(function(window, $) {
$(function() {
$(window.document).on('keyup', '.b-compose .b-header .inputosaurus-input input[type="text"]:first', function() {
var
$this = $(this),
value = $this.val()
;
if (value && value.match(/@/ig).length >= 2)
{
$this.val($this.val().replace(/\n| /ig, ','));
}
});
});
}(window, $))

View file

@ -1 +0,0 @@
1.1

View file

@ -2,6 +2,12 @@
class LdapContactsSuggestionsPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = 'Contacts suggestions (LDAP)',
VERSION = '2.0',
CATEGORY = 'Security',
DESCRIPTION = 'Plugin that adds functionality to get contacts from LDAP on compose page.';
public function Init() : void
{
$this->addHook('main.fabrica', 'MainFabrica');

View file

@ -1 +0,0 @@
1.0

View file

@ -6,6 +6,16 @@ use RainLoop\Plugins\Property;
class LdapIdentitiesPlugin extends AbstractPlugin
{
const
NAME = 'LDAP Identities',
VERSION = '2.0',
AUTHOR = 'FWest98',
URL = 'https://github.com/FWest98',
RELEASE = '2020-11-11',
REQUIRED = '2.1.0',
CATEGORY = 'Accounts',
DESCRIPTION = 'Plugin that adds functionality to import account identities from LDAP.';
public function __construct()
{
include_once __DIR__ . '/LdapIdentities.php';

View file

@ -1 +0,0 @@
1.0

View file

@ -2,6 +2,12 @@
class OverrideSmtpCredentialsPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = 'Override Smtp Credentials',
VERSION = '2.0',
CATEGORY = 'Filters',
DESCRIPTION = 'Plugin which allows you to override smtp credentials specified users.';
public function Init() : void
{
$this->addHook('filter.smtp-credentials', 'FilterSmtpCredentials');

View file

@ -1 +0,0 @@
1.0

View file

@ -2,6 +2,11 @@
class ProxyauthLoginExamplePlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = '',
CATEGORY = 'General',
DESCRIPTION = '';
public function Init() : void
{
$this->addHook('event.login-post-login-provide', 'EventLoginPostLoginProvide');

View file

@ -1 +0,0 @@
1.1

View file

@ -2,6 +2,12 @@
class SnowfallOnLoginScreenPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = 'Snowfall on login screen',
VERSION = '2.0',
CATEGORY = 'Fun',
DESCRIPTION = 'Snowfall on login screen plugin (just for fun).';
public function Init() : void
{
$this->addJs('js/snowfall.js');

View file

@ -1 +0,0 @@
1.0

View file

@ -2,6 +2,12 @@
class WhiteListPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = 'White list',
VERSION = '2.0',
CATEGORY = 'Login',
DESCRIPTION = 'Simple white list plugin (with wildcard and exceptions functionality).';
public function Init() : void
{
$this->addHook('filter.login-credentials', 'FilterLoginCredentials');

View file

@ -2,6 +2,54 @@
<?php
chdir(__DIR__);
$options = getopt('', ['aur','docker','plugins']);
if (isset($options['plugins'])) {
$destPath = "build/dist/releases/plugins/";
is_dir($destPath) || mkdir($destPath, 0777, true);
$manifest = [];
require 'snappymail/v/0.0.0/app/libraries/RainLoop/Plugins/AbstractPlugin.php';
foreach (glob('plugins/*', GLOB_NOSORT | GLOB_ONLYDIR) as $dir) {
require "{$dir}/index.php";
$name = basename($dir);
$class = new ReflectionClass(str_replace('-', '', $name) . 'Plugin');
$manifest_item = [];
foreach ($class->getConstants() as $key => $value) {
$manifest_item[\strtolower($key)] = $value;
}
$version = $manifest_item['version'];
if (0 < floatval($version)) {
echo "+ {$name} {$version}\n";
$manifest_item['type'] = 'plugin';
$manifest_item['id'] = $name;
$manifest_item['file'] = "{$dir}-{$version}.tgz";
ksort($manifest_item);
$manifest[$name] = $manifest_item;
$tar_destination = "{$destPath}{$name}-{$version}.tar";
$tgz_destination = "{$destPath}{$name}-{$version}.tgz";
@unlink($tgz_destination);
@unlink("{$tar_destination}.gz");
$tar = new PharData($tar_destination);
$tar->buildFromDirectory('./plugins/', "@{$name}@");
$tar->compress(Phar::GZ);
unlink($tar_destination);
rename("{$tar_destination}.gz", $tgz_destination);
} else {
echo "- {$name} {$version}\n";
}
}
ksort($manifest);
$manifest = json_encode(array_values($manifest));
$manifest = str_replace('{"', "\n\t{\n\t\t\"", $manifest);
$manifest = str_replace('"}', "\"\n\t}", $manifest);
$manifest = str_replace('}]', "}\n]", $manifest);
$manifest = str_replace('","', "\",\n\t\t\"", $manifest);
$manifest = str_replace('\/', '/', $manifest);
file_put_contents("{$destPath}packages.json", $manifest);
exit;
}
$gulp = trim(`which gulp`);
if (!$gulp) {
exit('gulp not installed, run as root: npm install --global gulp-cli');
@ -12,8 +60,6 @@ if (!$rollup) {
exit('rollup not installed, run as root: npm install --global rollup');
}
$options = getopt('', ['aur','docker']);
// Arch User Repository
// https://aur.archlinux.org/packages/snappymail/
$options['aur'] = isset($options['aur']);

View file

@ -989,7 +989,7 @@ class Actions
$aAttachmentsActions = array();
if ($this->GetCapa(false, $bMobile, Enumerations\Capa::ATTACHMENTS_ACTIONS)) {
if (!!\class_exists('ZipArchive')) {
if (\class_exists('ZipArchive')) {
$aAttachmentsActions[] = 'zip';
}
}

View file

@ -489,14 +489,14 @@ trait Admin
private function snappyMailRepo() : string
{
return 'https://snappymail.eu/repository/';
return 'https://snappymail.eu/repository/v2/';
}
private function rainLoopUpdatable() : bool
{
return file_exists(APP_INDEX_ROOT_PATH.'index.php') &&
is_writable(APP_INDEX_ROOT_PATH.'index.php') &&
is_writable(APP_INDEX_ROOT_PATH.'snappymail/') &&
return \file_exists(APP_INDEX_ROOT_PATH.'index.php') &&
\is_writable(APP_INDEX_ROOT_PATH.'index.php') &&
\is_writable(APP_INDEX_ROOT_PATH.'snappymail/') &&
APP_VERSION !== APP_DEV_VERSION
;
}
@ -684,23 +684,23 @@ trait Admin
}
}
$bResult = false;
if ('' !== $sResultId)
{
$bResult = \MailSo\Base\Utils::RecRmDir(APP_PLUGINS_PATH.$sResultId);
if ($bResult)
{
$bResult = '' !== $sResultId && static::deletePackageDir($sResultId);
if ($bResult) {
$this->pluginEnable($sResultId, false);
}
}
return $this->DefaultResponse(__FUNCTION__, $bResult);
}
private static function deletePackageDir(string $sId) : bool
{
return !\is_dir(APP_PLUGINS_PATH.$sId) || \MailSo\Base\Utils::RecRmDir(APP_PLUGINS_PATH.$sId);
}
private function downloadRemotePackageByUrl(string $sUrl) : string
{
$bResult = false;
$sTmp = APP_PRIVATE_DATA.\md5(\microtime(true).$sUrl).'.zip';
$sTmp = APP_PRIVATE_DATA.\md5(\microtime(true).$sUrl) . \substr($sUrl, -4);
$pDest = \fopen($sTmp, 'w+b');
if ($pDest)
{
@ -757,40 +757,19 @@ trait Admin
}
}
$sTmp = '';
$bResult = false;
if ('' !== $sRealFile)
{
$sTmp = $this->downloadRemotePackageByUrl($this->snappyMailRepo().$sRealFile);
}
if ('' !== $sTmp)
{
$oArchive = new \ZipArchive();
$oArchive->open($sTmp);
if ('plugin' === $sType)
{
$bResult = true;
if (\is_dir(APP_PLUGINS_PATH.$sId))
{
$bResult = \MailSo\Base\Utils::RecRmDir(APP_PLUGINS_PATH.$sId);
if (!$bResult)
{
$this->Logger()->Write('Cannot remove previous plugin folder: '.$sId, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
}
}
if ($bResult)
$sTmp = $sRealFile ? $this->downloadRemotePackageByUrl($this->snappyMailRepo().$sRealFile) : null;
if ($sTmp)
{
$oArchive = new \PharData($sTmp, 0, $sRealFile);
if (!\is_dir(APP_PLUGINS_PATH.$sId) || static::deletePackageDir($sId)) {
$bResult = $oArchive->extractTo(APP_PLUGINS_PATH);
if (!$bResult)
{
if (!$bResult) {
$this->Logger()->Write('Cannot extract package files: '.$oArchive->getStatusString(), \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
}
} else {
$this->Logger()->Write('Cannot remove previous plugin folder: '.$sId, \MailSo\Log\Enumerations\Type::ERROR, 'INSTALLER');
}
}
$oArchive->close();
\unlink($sTmp);
}

View file

@ -4,6 +4,17 @@ namespace RainLoop\Plugins;
abstract class AbstractPlugin
{
const
NAME = '',
AUTHOR = 'SnappyMail',
URL = 'https://snappymail.eu/',
VERSION = '0.0',
RELEASE = '2020-11-01',
REQUIRED = '2.0.0',
CATEGORY = 'General',
LICENSE = 'MIT',
DESCRIPTION = '';
/**
* @var \RainLoop\Plugins\Manager
*/

View file

@ -112,36 +112,18 @@ class Manager
public function CreatePluginByName(string $sName) : ?\RainLoop\Plugins\AbstractPlugin
{
$oPlugin = null;
if (\preg_match('/^[a-z0-9\-]+$/', $sName) &&
\file_exists(APP_PLUGINS_PATH.$sName.'/index.php'))
{
$sClassName = $this->convertPluginFolderNameToClassName($sName);
if (!\class_exists($sClassName))
{
include APP_PLUGINS_PATH.$sName.'/index.php';
}
if (\class_exists($sClassName))
{
$sClassName = $this->loadPluginByName($sName);
if ($sClassName) {
$oPlugin = new $sClassName();
if ($oPlugin instanceof \RainLoop\Plugins\AbstractPlugin)
{
$oPlugin
->SetName($sName)
->SetPath(APP_PLUGINS_PATH.$sName)
->SetVersion(\file_exists(APP_PLUGINS_PATH.$sName.'/VERSION') ?
\file_get_contents(APP_PLUGINS_PATH.$sName.'/VERSION') : '')
->SetVersion($sClassName::VERSION)
->SetPluginManager($this)
->SetPluginConfig(new \RainLoop\Config\Plugin($sName, $oPlugin->ConfigMap()))
;
}
else
{
$oPlugin = null;
}
}
}
return $oPlugin;
}
@ -156,17 +138,13 @@ class Manager
foreach ($aGlob as $sPathName)
{
$sName = \basename($sPathName);
if (\preg_match('/^[a-z0-9\-]+$/', $sName) &&
\file_exists($sPathName.'/index.php'))
{
$sClassName = $this->loadPluginByName($sName);
$aList[] = array(
$sName,
\file_exists($sPathName.'/VERSION') ?
\file_get_contents($sPathName.'/VERSION') : '0.0'
$sClassName::VERSION
);
}
}
}
else
{
$this->Actions()->Logger()->Write('Cannot get installed plugins from '.APP_PLUGINS_PATH,
@ -184,6 +162,21 @@ class Manager
return \implode($aParts).'Plugin';
}
public function loadPluginByName(string $sName) : ?string
{
if (\preg_match('/^[a-z0-9\-]+$/', $sName)
&& \file_exists(APP_PLUGINS_PATH.$sName.'/index.php'))
{
$sClassName = $this->convertPluginFolderNameToClassName($sName);
if (!\class_exists($sClassName)) {
include APP_PLUGINS_PATH.$sName.'/index.php';
}
if (\class_exists($sClassName) && \is_subclass_of($sClassName, 'RainLoop\\Plugins\\AbstractPlugin')) {
return $sClassName;
}
}
}
public function Actions() : \RainLoop\Actions
{
return $this->oActions;

View file

@ -102,7 +102,7 @@
<div class="control-group">
<div class="controls">
<a class="btn" data-bind="command: saveNewAdminPasswordCommand, css: { 'btn-success': adminPasswordUpdateSuccess, 'btn-danger': adminPasswordUpdateError }">
<i class="fontastic" data-bind="css: {'icon-white': adminPasswordUpdateSuccess() || adminPasswordUpdateError() }">🔑></i>
<i class="fontastic" data-bind="css: {'icon-white': adminPasswordUpdateSuccess() || adminPasswordUpdateError() }">🔑</i>
<span data-i18n="TAB_SECURITY/BUTTON_UPDATE_PASSWORD"></span>
</a>
</div>