mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-01-01 04:22:15 +08:00
Get a working Sieve scripts manager
This commit is contained in:
parent
a31834458b
commit
e3125ebfff
24 changed files with 439 additions and 304 deletions
|
@ -379,6 +379,8 @@ export const Notification = {
|
|||
|
||||
CantSaveFilters: 351,
|
||||
CantGetFilters: 352,
|
||||
CantActivateFiltersScript: 351, // TODO: 353
|
||||
CantDeleteFiltersScript: 351, // TODO: 354
|
||||
FiltersAreNotCorrect: 355,
|
||||
|
||||
CantCreateFolder: 400,
|
||||
|
|
|
@ -10,21 +10,23 @@ class SieveScriptModel extends AbstractModel
|
|||
|
||||
this.addObservables({
|
||||
name: '',
|
||||
nameError: false,
|
||||
nameFocused: false,
|
||||
|
||||
active: false,
|
||||
|
||||
body: '',
|
||||
|
||||
nameError: false,
|
||||
bodyError: false,
|
||||
deleteAccess: false,
|
||||
canBeDeleted: false
|
||||
canBeDeleted: false,
|
||||
hasChanges: false
|
||||
});
|
||||
|
||||
this.filters = ko.observableArray([]);
|
||||
// this.saving = ko.observable(false).extend({ throttle: 200 });
|
||||
|
||||
this.addSubscribables({
|
||||
name: sValue => this.nameError(!sValue)
|
||||
name: () => this.hasChanges(true),
|
||||
filters: () => this.hasChanges(true),
|
||||
body: () => this.hasChanges(true)
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -34,20 +36,17 @@ class SieveScriptModel extends AbstractModel
|
|||
}
|
||||
|
||||
verify() {
|
||||
if (!this.name()) {
|
||||
this.nameError(true);
|
||||
return false;
|
||||
}
|
||||
this.nameError(false);
|
||||
return true;
|
||||
this.nameError(!this.name().trim());
|
||||
this.bodyError(this.allowFilters() ? !this.filters().length : !this.body().trim());
|
||||
return !this.nameError() && !this.bodyError();
|
||||
}
|
||||
|
||||
toJson() {
|
||||
return {
|
||||
name: this.name(),
|
||||
active: this.active ? '1' : '0',
|
||||
body: this.body,
|
||||
// filters: this.filters()
|
||||
active: this.active() ? '1' : '0',
|
||||
body: this.body(),
|
||||
filters: this.filters().map(item => item.toJson())
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -66,12 +65,14 @@ class SieveScriptModel extends AbstractModel
|
|||
static reviveFromJson(json) {
|
||||
const script = super.reviveFromJson(json);
|
||||
if (script) {
|
||||
script.filters([]);
|
||||
if (script.allowFilters() && Array.isNotEmpty(json.filters)) {
|
||||
script.filters(
|
||||
json.filters.map(aData => FilterModel.reviveFromJson(aData)).filter(v => v)
|
||||
);
|
||||
} else {
|
||||
script.filters([]);
|
||||
}
|
||||
script.hasChanges(false);
|
||||
}
|
||||
return script;
|
||||
}
|
||||
|
|
|
@ -236,6 +236,30 @@ class RemoteUserFetch extends AbstractFetchRemote {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
* @param {SieveScriptModel} script
|
||||
*/
|
||||
filtersScriptSave(fCallback, script) {
|
||||
this.defaultRequest(fCallback, 'FiltersScriptSave', script.toJson());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
* @param {string} name
|
||||
*/
|
||||
filtersScriptActivate(fCallback, name) {
|
||||
this.defaultRequest(fCallback, 'FiltersScriptActivate', {name:name});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
* @param {string} name
|
||||
*/
|
||||
filtersScriptDelete(fCallback, name) {
|
||||
this.defaultRequest(fCallback, 'FiltersScriptDelete', {name:name});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
*/
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
import ko from 'ko';
|
||||
|
||||
import { delegateRunOnDestroy } from 'Common/UtilsUser';
|
||||
import { StorageResultType, Notification } from 'Common/Enums';
|
||||
import { getNotification } from 'Common/Translator';
|
||||
|
||||
import FilterStore from 'Stores/User/Filter';
|
||||
import SieveStore from 'Stores/User/Sieve';
|
||||
import Remote from 'Remote/User/Fetch';
|
||||
|
||||
import { FilterModel } from 'Model/Filter';
|
||||
import { SieveScriptModel } from 'Model/SieveScript';
|
||||
|
||||
import { showScreenPopup } from 'Knoin/Knoin';
|
||||
|
||||
class FiltersUserSettings {
|
||||
constructor() {
|
||||
this.filters = FilterStore.filters;
|
||||
this.sieve = SieveStore;
|
||||
|
||||
this.scripts = SieveStore.scripts;
|
||||
this.loading = ko.observable(false).extend({ throttle: 200 });
|
||||
|
||||
ko.addObservablesTo(this, {
|
||||
serverError: false,
|
||||
|
@ -33,23 +33,17 @@ class FiltersUserSettings {
|
|||
}
|
||||
|
||||
updateList() {
|
||||
if (!this.filters.loading()) {
|
||||
this.filters.loading(true);
|
||||
if (!this.loading()) {
|
||||
this.loading(true);
|
||||
|
||||
Remote.filtersGet((result, data) => {
|
||||
this.filters.loading(false);
|
||||
this.loading(false);
|
||||
this.serverError(false);
|
||||
this.scripts([]);
|
||||
|
||||
if (StorageResultType.Success === result && data && data.Result && Array.isArray(data.Result.Filters)) {
|
||||
if (StorageResultType.Success === result && data && data.Result) {
|
||||
this.serverError(false);
|
||||
|
||||
this.filters(
|
||||
data.Result.Filters.map(aItem => FilterModel.reviveFromJson(aItem)).filter(v => v)
|
||||
);
|
||||
|
||||
FilterStore.modules(data.Result.Capa);
|
||||
|
||||
SieveStore.capa(data.Result.Capa);
|
||||
/*
|
||||
this.scripts(
|
||||
|
@ -60,20 +54,9 @@ class FiltersUserSettings {
|
|||
value = SieveScriptModel.reviveFromJson(value);
|
||||
value && this.scripts.push(value)
|
||||
});
|
||||
|
||||
FilterStore.raw(data.Result.Scripts['rainloop.user.raw'].body);
|
||||
FilterStore.capa(data.Result.Capa.join(' '));
|
||||
// this.filterRaw.active(data.Result.Scripts['rainloop.user.raw'].active);
|
||||
// this.filterRaw.allow(!!data.Result.RawIsAllow);
|
||||
} else {
|
||||
this.filters([]);
|
||||
FilterStore.modules({});
|
||||
|
||||
this.scripts([]);
|
||||
SieveStore.capa([]);
|
||||
|
||||
FilterStore.raw('');
|
||||
FilterStore.capa({});
|
||||
|
||||
this.serverError(true);
|
||||
this.serverErrorDesc(
|
||||
data && data.ErrorCode ? getNotification(data.ErrorCode) : getNotification(Notification.CantGetFilters)
|
||||
|
@ -106,13 +89,42 @@ class FiltersUserSettings {
|
|||
]);
|
||||
}
|
||||
|
||||
deleteScript() {
|
||||
// TODO
|
||||
deleteScript(script) {
|
||||
if (!script.active()) {
|
||||
Remote.filtersScriptDelete(
|
||||
(result, data) => {
|
||||
if (StorageResultType.Success === result && data && data.Result) {
|
||||
this.scripts.remove(script);
|
||||
delegateRunOnDestroy(script);
|
||||
} else {
|
||||
this.saveError(true);
|
||||
this.saveErrorText((data && data.ErrorCode)
|
||||
? (data.ErrorMessageAdditional || getNotification(data.ErrorCode))
|
||||
: getNotification(Notification.CantActivateFiltersScript)
|
||||
);
|
||||
}
|
||||
},
|
||||
script.name()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
toggleScript(script) {
|
||||
// TODO: activate/deactivate script
|
||||
script.active(!script.active());
|
||||
let name = script.active() ? '' : script.name();
|
||||
Remote.filtersScriptActivate(
|
||||
(result, data) => {
|
||||
if (StorageResultType.Success === result && data && data.Result) {
|
||||
this.scripts().forEach(script => script.active(script.name() === name));
|
||||
} else {
|
||||
this.saveError(true);
|
||||
this.saveErrorText((data && data.ErrorCode)
|
||||
? (data.ErrorMessageAdditional || getNotification(data.ErrorCode))
|
||||
: getNotification(Notification.CantActivateFiltersScript)
|
||||
);
|
||||
}
|
||||
},
|
||||
name
|
||||
);
|
||||
}
|
||||
|
||||
onBuild(oDom) {
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
import ko from 'ko';
|
||||
|
||||
class FilterUserStore {
|
||||
constructor() {
|
||||
ko.addObservablesTo(this, {
|
||||
capa: '',
|
||||
modules: [],
|
||||
raw: ''
|
||||
});
|
||||
|
||||
this.filters = ko.observableArray([]);
|
||||
|
||||
this.filters.loading = ko.observable(false).extend({ throttle: 200 });
|
||||
this.filters.saving = ko.observable(false).extend({ throttle: 200 });
|
||||
}
|
||||
}
|
||||
|
||||
export default new FilterUserStore();
|
|
@ -50,3 +50,8 @@ html.rl-mobile .b-settings-filters {
|
|||
.filter-item .filter-sub-name {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.b-filter-script textarea {
|
||||
height: 300px;
|
||||
font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ import { FiltersAction, FilterConditionField, FilterConditionType } from 'Common
|
|||
import { defaultOptionsAfterRender } from 'Common/Utils';
|
||||
import { i18n, initOnStartOrLangChange } from 'Common/Translator';
|
||||
|
||||
import FilterStore from 'Stores/User/Filter';
|
||||
import FolderStore from 'Stores/User/Folder';
|
||||
import SieveStore from 'Stores/User/Sieve';
|
||||
|
||||
import { popup, command } from 'Knoin/Knoin';
|
||||
import { AbstractViewNext } from 'Knoin/AbstractViewNext';
|
||||
|
@ -25,7 +25,7 @@ class FilterPopupView extends AbstractViewNext {
|
|||
selectedFolderValue: ''
|
||||
});
|
||||
|
||||
this.modules = FilterStore.modules;
|
||||
this.modules = SieveStore.capa;
|
||||
|
||||
this.fTrueCallback = null;
|
||||
|
||||
|
|
|
@ -3,12 +3,13 @@ import ko from 'ko';
|
|||
import { delegateRunOnDestroy } from 'Common/UtilsUser';
|
||||
import { StorageResultType, Notification } from 'Common/Enums';
|
||||
import { getNotification } from 'Common/Translator';
|
||||
import { i18nToNodes } from 'Common/Translator';
|
||||
|
||||
import Remote from 'Remote/User/Fetch';
|
||||
import FilterStore from 'Stores/User/Filter';
|
||||
import FilterModel from 'Model/Filter';
|
||||
import SieveStore from 'Stores/User/Sieve';
|
||||
|
||||
import { popup, showScreenPopup, command } from 'Knoin/Knoin';
|
||||
import { popup, showScreenPopup/*, command*/ } from 'Knoin/Knoin';
|
||||
import { AbstractViewNext } from 'Knoin/AbstractViewNext';
|
||||
|
||||
@popup({
|
||||
|
@ -19,78 +20,46 @@ class SieveScriptPopupView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
// this.filters = FilterStore.filters;
|
||||
this.filters = ko.observableArray([]);
|
||||
this.filters.loading = ko.observable(false).extend({ throttle: 200 });
|
||||
this.filters.saving = ko.observable(false).extend({ throttle: 200 });
|
||||
|
||||
this.modules = FilterStore.modules;
|
||||
|
||||
this.script = {
|
||||
filters: FilterStore.filters,
|
||||
saving: () => FilterStore.filters.saving()
|
||||
};
|
||||
|
||||
ko.addObservablesTo(this, {
|
||||
isNew: true,
|
||||
serverError: false,
|
||||
serverErrorDesc: '',
|
||||
saveError: false,
|
||||
saveErrorText: '',
|
||||
haveChanges: false,
|
||||
filterRaw: ''
|
||||
rawActive: false,
|
||||
script: null
|
||||
});
|
||||
|
||||
this.serverError.subscribe(value => value || this.serverErrorDesc(''), this);
|
||||
|
||||
// this.filterRaw = FilterStore.raw;
|
||||
this.filterRaw.capa = FilterStore.capa;
|
||||
this.filterRaw.active = ko.observable(false);
|
||||
this.filterRaw.allow = ko.observable(false);
|
||||
this.filterRaw.error = ko.observable(false);
|
||||
this.sieveCapabilities = SieveStore.capa.join(' ');
|
||||
this.saving = false;
|
||||
|
||||
this.filterForDeletion = ko.observable(null).deleteAccessHelper();
|
||||
|
||||
this.filters.subscribe(() => this.haveChanges(true));
|
||||
|
||||
this.filterRaw.subscribe(() => {
|
||||
this.haveChanges(true);
|
||||
this.filterRaw.error(false);
|
||||
});
|
||||
|
||||
this.haveChanges.subscribe(() => this.saveErrorText(''));
|
||||
|
||||
this.filterRaw.active.subscribe(() => {
|
||||
this.haveChanges(true);
|
||||
this.filterRaw.error(false);
|
||||
});
|
||||
}
|
||||
|
||||
@command((self) => self.haveChanges())
|
||||
// @command()
|
||||
saveScriptCommand() {
|
||||
if (!this.filters.saving()) {
|
||||
if (this.filterRaw.active() && !this.filterRaw().trim()) {
|
||||
this.filterRaw.error(true);
|
||||
let script = this.script();
|
||||
if (!this.saving/* && script.hasChanges()*/) {
|
||||
if (!script.verify()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.filters.saving(true);
|
||||
this.saveErrorText('');
|
||||
this.saving = true;
|
||||
this.saveError(false);
|
||||
|
||||
Remote.filtersSave(
|
||||
Remote.filtersScriptSave(
|
||||
(result, data) => {
|
||||
this.filters.saving(false);
|
||||
this.saving = false;
|
||||
|
||||
if (StorageResultType.Success === result && data && data.Result) {
|
||||
this.haveChanges(false);
|
||||
} else if (data && data.ErrorCode) {
|
||||
this.saveErrorText(data.ErrorMessageAdditional || getNotification(data.ErrorCode));
|
||||
script.hasChanges(false);
|
||||
} else {
|
||||
this.saveErrorText(getNotification(Notification.CantSaveFilters));
|
||||
this.saveError(true);
|
||||
this.saveErrorText((data && data.ErrorCode)
|
||||
? (data.ErrorMessageAdditional || getNotification(data.ErrorCode))
|
||||
: getNotification(Notification.CantSaveFilters)
|
||||
);
|
||||
}
|
||||
},
|
||||
this.filters(),
|
||||
this.filterRaw(),
|
||||
this.filterRaw.active()
|
||||
script
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -98,19 +67,18 @@ class SieveScriptPopupView extends AbstractViewNext {
|
|||
}
|
||||
|
||||
deleteFilter(filter) {
|
||||
this.filters.remove(filter);
|
||||
this.script().filters.remove(filter);
|
||||
delegateRunOnDestroy(filter);
|
||||
}
|
||||
|
||||
addFilter() {
|
||||
/* this = SieveScriptModel */
|
||||
const filter = new FilterModel();
|
||||
|
||||
filter.generateID();
|
||||
showScreenPopup(require('View/Popup/Filter'), [
|
||||
filter,
|
||||
() => {
|
||||
this.filters.push(filter);
|
||||
this.filterRaw.active(false);
|
||||
},
|
||||
false
|
||||
]);
|
||||
|
@ -118,19 +86,16 @@ class SieveScriptPopupView extends AbstractViewNext {
|
|||
|
||||
editFilter(filter) {
|
||||
const clonedFilter = filter.cloneSelf();
|
||||
|
||||
showScreenPopup(require('View/Popup/Filter'), [
|
||||
clonedFilter,
|
||||
() => {
|
||||
const filters = this.filters(),
|
||||
const script = this.script(),
|
||||
filters = script.filters(),
|
||||
index = filters.indexOf(filter);
|
||||
|
||||
if (-1 < index && filters[index]) {
|
||||
if (-1 < index) {
|
||||
delegateRunOnDestroy(filters[index]);
|
||||
filters[index] = clonedFilter;
|
||||
|
||||
this.filters(filters);
|
||||
this.haveChanges(true);
|
||||
script.filters(filters);
|
||||
}
|
||||
},
|
||||
true
|
||||
|
@ -141,36 +106,22 @@ class SieveScriptPopupView extends AbstractViewNext {
|
|||
oDom.addEventListener('click', event => {
|
||||
const el = event.target.closestWithin('.filter-item .e-action', oDom),
|
||||
filter = el && ko.dataFor(el);
|
||||
filter && this.editFilter(ko.dataFor(el));
|
||||
filter && this.editFilter(filter);
|
||||
});
|
||||
}
|
||||
|
||||
onShow(oScript, fTrueCallback, bEdit) {
|
||||
this.clearPopup();
|
||||
|
||||
this.fTrueCallback = fTrueCallback;
|
||||
this.filters(oScript.filters());
|
||||
|
||||
this.filterRaw(oScript.body());
|
||||
this.filterRaw.active(!oScript.allowFilters());
|
||||
this.filterRaw.error(false);
|
||||
|
||||
this.script(oScript);
|
||||
this.rawActive(!oScript.allowFilters());
|
||||
this.isNew(!bEdit);
|
||||
|
||||
if (!bEdit && oScript) {
|
||||
// oScript.nameFocused(true);
|
||||
}
|
||||
this.saveError(false);
|
||||
}
|
||||
|
||||
onShowWithDelay() {
|
||||
// Sometimes not everything is translated, try again
|
||||
i18nToNodes(this.viewModelDom);
|
||||
}
|
||||
|
||||
clearPopup() {
|
||||
this.isNew(true);
|
||||
this.fTrueCallback = null;
|
||||
this.filters([]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { SieveScriptPopupView, SieveScriptPopupView as default };
|
||||
|
|
|
@ -326,6 +326,17 @@ class ManageSieveClient extends \MailSo\Net\NetClient
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \MailSo\Net\Exceptions\Exception
|
||||
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
|
||||
*/
|
||||
public function RenameScript(string $sOldName, string $sNewName) : self
|
||||
{
|
||||
$this->sendRequestWithCheck('RENAMESCRIPT "'.$sOldName.'" "'.$sNewName.'"');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \MailSo\Net\Exceptions\Exception
|
||||
* @throws \MailSo\Sieve\Exceptions\NegativeResponseException
|
||||
|
|
|
@ -76,6 +76,64 @@ trait Filters
|
|||
$aFilters, $sRaw, $bRawIsActive));
|
||||
}
|
||||
|
||||
public function DoFiltersScriptSave() : array
|
||||
{
|
||||
$oAccount = $this->getAccountFromToken();
|
||||
|
||||
if (!$this->GetCapa(false, false, Capa::FILTERS, $oAccount)) {
|
||||
return $this->FalseResponse(__FUNCTION__);
|
||||
}
|
||||
|
||||
$sName = $this->GetActionParam('name', '');
|
||||
|
||||
$aFilters = array();
|
||||
if (\RainLoop\Providers\Filters\SieveStorage::SIEVE_FILE_NAME === $sName) {
|
||||
$aIncFilters = $this->GetActionParam('filters', array());
|
||||
foreach ($aIncFilters as $aFilter) {
|
||||
if (\is_array($aFilter)) {
|
||||
$oFilter = new \RainLoop\Providers\Filters\Classes\Filter();
|
||||
if ($oFilter->FromJSON($aFilter)) {
|
||||
$aFilters[] = $oFilter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->GetActionParam('active', false)) {
|
||||
// $this->FiltersProvider()->ActivateScript($oAccount, $sName);
|
||||
}
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__, $this->FiltersProvider()->Save(
|
||||
$oAccount, $sName, $aFilters, $this->GetActionParam('body', '')
|
||||
));
|
||||
}
|
||||
|
||||
public function DoFiltersScriptActivate() : array
|
||||
{
|
||||
$oAccount = $this->getAccountFromToken();
|
||||
|
||||
if (!$this->GetCapa(false, false, Capa::FILTERS, $oAccount)) {
|
||||
return $this->FalseResponse(__FUNCTION__);
|
||||
}
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__, $this->FiltersProvider()->ActivateScript(
|
||||
$oAccount, $this->GetActionParam('name', '')
|
||||
));
|
||||
}
|
||||
|
||||
public function DoFiltersScriptDelete() : array
|
||||
{
|
||||
$oAccount = $this->getAccountFromToken();
|
||||
|
||||
if (!$this->GetCapa(false, false, Capa::FILTERS, $oAccount)) {
|
||||
return $this->FalseResponse(__FUNCTION__);
|
||||
}
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__, $this->FiltersProvider()->DeleteScript(
|
||||
$oAccount, $this->GetActionParam('name', '')
|
||||
));
|
||||
}
|
||||
|
||||
protected function FiltersProvider() : \RainLoop\Providers\Filters
|
||||
{
|
||||
if (!$this->oFiltersProvider) {
|
||||
|
|
|
@ -35,6 +35,8 @@ class Notifications
|
|||
|
||||
const CantSaveFilters = 351;
|
||||
const CantGetFilters = 352;
|
||||
const CantActivateFiltersScript = 351; // TODO: 353
|
||||
const CantDeleteFiltersScript = 351; // TODO: 354
|
||||
const FiltersAreNotCorrect = 355;
|
||||
|
||||
const CantCreateFolder = 400;
|
||||
|
|
|
@ -14,47 +14,73 @@ class Filters extends \RainLoop\Providers\AbstractProvider
|
|||
$this->oDriver = $oDriver;
|
||||
}
|
||||
|
||||
private static function handleException(\Throwable $oException, int $defNotification) : void
|
||||
{
|
||||
if ($oException instanceof \MailSo\Net\Exceptions\SocketCanNotConnectToHostException) {
|
||||
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ConnectionError, $oException);
|
||||
}
|
||||
|
||||
if ($oException instanceof \MailSo\Sieve\Exceptions\NegativeResponseException) {
|
||||
throw new \RainLoop\Exceptions\ClientException(
|
||||
\RainLoop\Notifications::ClientViewError, $oException, \implode("\r\n", $oException->GetResponses())
|
||||
);
|
||||
}
|
||||
|
||||
throw new \RainLoop\Exceptions\ClientException($defNotification, $oException);
|
||||
}
|
||||
|
||||
public function Load(\RainLoop\Model\Account $oAccount, bool $bAllowRaw = false) : array
|
||||
{
|
||||
try
|
||||
{
|
||||
return $this->IsActive() ? $this->oDriver->Load($oAccount, $bAllowRaw) : array();
|
||||
}
|
||||
catch (\MailSo\Net\Exceptions\SocketCanNotConnectToHostException $oException)
|
||||
{
|
||||
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ConnectionError, $oException);
|
||||
}
|
||||
catch (\Throwable $oException)
|
||||
{
|
||||
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantGetFilters, $oException);
|
||||
static::handleException($oException, \RainLoop\Notifications::CantGetFilters);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function Save(\RainLoop\Model\Account $oAccount, array $aFilters, string $sRaw = '', bool $bRawIsActive = false) : bool
|
||||
public function Save(\RainLoop\Model\Account $oAccount, string $sScriptName, array $aFilters, string $sRaw = '') : bool
|
||||
{
|
||||
try
|
||||
{
|
||||
return $this->IsActive() ? $this->oDriver->Save(
|
||||
$oAccount, $aFilters, $sRaw, $bRawIsActive) : false;
|
||||
}
|
||||
catch (\MailSo\Net\Exceptions\SocketCanNotConnectToHostException $oException)
|
||||
{
|
||||
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::ConnectionError, $oException);
|
||||
}
|
||||
catch (\MailSo\Sieve\Exceptions\NegativeResponseException $oException)
|
||||
{
|
||||
throw new \RainLoop\Exceptions\ClientException(
|
||||
\RainLoop\Notifications::ClientViewError, $oException,
|
||||
\implode("\r\n", $oException->GetResponses()));
|
||||
return $this->IsActive()
|
||||
? $this->oDriver->Save($oAccount, $sScriptName, $aFilters, $sRaw)
|
||||
: false;
|
||||
}
|
||||
catch (\Throwable $oException)
|
||||
{
|
||||
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CantSaveFilters, $oException);
|
||||
static::handleException($oException. \RainLoop\Notifications::CantSaveFilters);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
public function ActivateScript(\RainLoop\Model\Account $oAccount, string $sScriptName)
|
||||
{
|
||||
try
|
||||
{
|
||||
return $this->IsActive()
|
||||
? $this->oDriver->Activate($oAccount, $sScriptName)
|
||||
: false;
|
||||
}
|
||||
catch (\Throwable $oException)
|
||||
{
|
||||
static::handleException($oException. \RainLoop\Notifications::CantActivateFiltersScript);
|
||||
}
|
||||
}
|
||||
|
||||
public function DeleteScript(\RainLoop\Model\Account $oAccount, string $sScriptName)
|
||||
{
|
||||
try
|
||||
{
|
||||
return $this->IsActive()
|
||||
? $this->oDriver->Delete($oAccount, $sScriptName)
|
||||
: false;
|
||||
}
|
||||
catch (\Throwable $oException)
|
||||
{
|
||||
static::handleException($oException. \RainLoop\Notifications::CantDeleteFiltersScript);
|
||||
}
|
||||
}
|
||||
|
||||
public function IsActive() : bool
|
||||
|
|
|
@ -6,5 +6,9 @@ interface FiltersInterface
|
|||
{
|
||||
public function Load(\RainLoop\Model\Account $oAccount, bool $bAllowRaw = false) : array;
|
||||
|
||||
public function Save(\RainLoop\Model\Account $oAccount, array $aFilters) : bool;
|
||||
public function Save(\RainLoop\Model\Account $oAccount, string $sScriptName, array $aFilters, string $sRaw = '') : bool;
|
||||
|
||||
public function Activate(\RainLoop\Model\Account $oAccount, string $sScriptName) : bool;
|
||||
|
||||
public function Delete(\RainLoop\Model\Account $oAccount, string $sScriptName) : bool;
|
||||
}
|
||||
|
|
|
@ -39,52 +39,67 @@ class SieveStorage implements FiltersInterface
|
|||
$this->bUtf8FolderName = !!$this->oConfig->Get('labs', 'sieve_utf8_folder_name', true);
|
||||
}
|
||||
|
||||
protected function getConnection(\RainLoop\Model\Account $oAccount) : ?\MailSo\Sieve\ManageSieveClient
|
||||
{
|
||||
$oSieveClient = new \MailSo\Sieve\ManageSieveClient();
|
||||
$oSieveClient->SetLogger($this->oLogger);
|
||||
$oSieveClient->SetTimeOuts(10, (int) \RainLoop\Api::Config()->Get('labs', 'sieve_timeout', 10));
|
||||
return $oAccount->SieveConnectAndLoginHelper($this->oPlugins, $oSieveClient, $this->oConfig)
|
||||
? $oSieveClient
|
||||
: null;
|
||||
}
|
||||
|
||||
public function Load(\RainLoop\Model\Account $oAccount, bool $bAllowRaw = false) : array
|
||||
{
|
||||
$aModules = array();
|
||||
$aFilters = array();
|
||||
$aScripts = array();
|
||||
|
||||
$oSieveClient = new \MailSo\Sieve\ManageSieveClient();
|
||||
$oSieveClient->SetLogger($this->oLogger);
|
||||
$oSieveClient->SetTimeOuts(10, (int) $this->oConfig->Get('labs', 'sieve_timeout', 10));
|
||||
|
||||
if ($oAccount->SieveConnectAndLoginHelper($this->oPlugins, $oSieveClient, $this->oConfig)) {
|
||||
$oSieveClient = $this->getConnection($oAccount);
|
||||
if ($oSieveClient) {
|
||||
$aModules = $oSieveClient->Modules();
|
||||
\sort($aModules);
|
||||
|
||||
$aList = $oSieveClient->ListScripts();
|
||||
|
||||
if (!empty($aList[self::SIEVE_FILE_NAME])) {
|
||||
$sS = $oSieveClient->GetScript(self::SIEVE_FILE_NAME);
|
||||
if ($sS) {
|
||||
$aFilters = $this->fileStringToCollection($sS);
|
||||
}
|
||||
}
|
||||
|
||||
if ($bAllowRaw) {
|
||||
foreach ($aList as $name => $active) {
|
||||
if ($name != self::SIEVE_FILE_NAME) {
|
||||
foreach ($aList as $name => $active) {
|
||||
if ($name != self::SIEVE_FILE_NAME) {
|
||||
if ($bAllowRaw) {
|
||||
$aScripts[$name] = array(
|
||||
'@Object' => 'Object/SieveScript',
|
||||
'name' => $name,
|
||||
'active' => $active,
|
||||
'body' => $oSieveClient->GetScript($name) // \trim() ?
|
||||
);
|
||||
} else {
|
||||
$aScripts[$name] = array(
|
||||
'@Object' => 'Object/SieveScript',
|
||||
'name' => $name,
|
||||
'active' => $active,
|
||||
'body' => $oSieveClient->GetScript($name), // \trim() ?
|
||||
'filters' => $aFilters
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$sS = $oSieveClient->GetScript(self::SIEVE_FILE_NAME);
|
||||
if ($sS) {
|
||||
$aFilters = $this->fileStringToCollection($sS);
|
||||
}
|
||||
$aScripts[$name] = array(
|
||||
'@Object' => 'Object/SieveScript',
|
||||
'name' => $name,
|
||||
'active' => $active,
|
||||
'body' => $oSieveClient->GetScript($name), // \trim() ?
|
||||
'filters' => $aFilters
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$oSieveClient->LogoutAndDisconnect();
|
||||
}
|
||||
|
||||
if (!isset($aList[self::SIEVE_FILE_NAME_RAW])) {
|
||||
if (!isset($aList[self::SIEVE_FILE_NAME])) {
|
||||
$aScripts[$name] = array(
|
||||
'@Object' => 'Object/SieveScript',
|
||||
'name' => self::SIEVE_FILE_NAME,
|
||||
'active' => false,
|
||||
'body' => '',
|
||||
'filters' => []
|
||||
);
|
||||
}
|
||||
|
||||
if ($bAllowRaw && !isset($aList[self::SIEVE_FILE_NAME_RAW])) {
|
||||
$aScripts[$name] = array(
|
||||
'@Object' => 'Object/SieveScript',
|
||||
'name' => self::SIEVE_FILE_NAME_RAW,
|
||||
|
@ -96,55 +111,52 @@ class SieveStorage implements FiltersInterface
|
|||
\ksort($aScripts);
|
||||
|
||||
return array(
|
||||
'RawIsAllow' => $bAllowRaw,
|
||||
'Filters' => $aFilters,
|
||||
'Capa' => $aModules,
|
||||
'Scripts' => $aScripts
|
||||
);
|
||||
}
|
||||
|
||||
public function Save(\RainLoop\Model\Account $oAccount, array $aFilters, string $sRaw = '', bool $bRawIsActive = false) : bool
|
||||
public function Save(\RainLoop\Model\Account $oAccount, string $sScriptName, array $aFilters, string $sRaw = '') : bool
|
||||
{
|
||||
$oSieveClient = new \MailSo\Sieve\ManageSieveClient();
|
||||
$oSieveClient->SetLogger($this->oLogger);
|
||||
$oSieveClient->SetTimeOuts(10, (int) \RainLoop\Api::Config()->Get('labs', 'sieve_timeout', 10));
|
||||
|
||||
if ($oAccount->SieveConnectAndLoginHelper($this->oPlugins, $oSieveClient, $this->oConfig))
|
||||
{
|
||||
$aList = $oSieveClient->ListScripts();
|
||||
|
||||
if ($bRawIsActive)
|
||||
{
|
||||
if (!empty($sRaw))
|
||||
{
|
||||
$oSieveClient->PutScript(self::SIEVE_FILE_NAME_RAW, $sRaw);
|
||||
$oSieveClient->SetActiveScript(self::SIEVE_FILE_NAME_RAW);
|
||||
}
|
||||
else if (isset($aList[self::SIEVE_FILE_NAME_RAW]))
|
||||
{
|
||||
$oSieveClient->DeleteScript(self::SIEVE_FILE_NAME_RAW);
|
||||
if (self::SIEVE_FILE_NAME === $sScriptName) {
|
||||
$sRaw = $this->collectionToFileString($aFilters);
|
||||
}
|
||||
$oSieveClient = $this->getConnection($oAccount);
|
||||
if ($oSieveClient) {
|
||||
if (empty($sRaw)) {
|
||||
$aList = $oSieveClient->ListScripts();
|
||||
if (isset($aList[$sScriptName])) {
|
||||
$oSieveClient->DeleteScript($sScriptName);
|
||||
}
|
||||
} else {
|
||||
$oSieveClient->PutScript($sScriptName, $sRaw);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUserFilter = $this->collectionToFileString($aFilters);
|
||||
|
||||
if (!empty($sUserFilter))
|
||||
{
|
||||
$oSieveClient->PutScript(self::SIEVE_FILE_NAME, $sUserFilter);
|
||||
$oSieveClient->SetActiveScript(self::SIEVE_FILE_NAME);
|
||||
}
|
||||
else if (isset($aList[self::SIEVE_FILE_NAME]))
|
||||
{
|
||||
$oSieveClient->DeleteScript(self::SIEVE_FILE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
$oSieveClient->LogoutAndDisconnect();
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If $sScriptName is the empty string (i.e., ""), then any active script is disabled.
|
||||
*/
|
||||
public function Activate(\RainLoop\Model\Account $oAccount, string $sScriptName) : bool
|
||||
{
|
||||
$oSieveClient = $this->getConnection($oAccount);
|
||||
if ($oSieveClient) {
|
||||
$oSieveClient->SetActiveScript(\trim($sScriptName));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function Delete(\RainLoop\Model\Account $oAccount, string $sScriptName) : bool
|
||||
{
|
||||
$oSieveClient = $this->getConnection($oAccount);
|
||||
if ($oSieveClient) {
|
||||
$oSieveClient->DeleteScript(\trim($sScriptName));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -349,6 +349,15 @@ en:
|
|||
VACATION_RECIPIENTS_LABEL: "Recipients (comma separated)"
|
||||
REJECT_MESSAGE_LABEL: "Reject message"
|
||||
ALL_INCOMING_MESSAGES_DESC: "All incoming messages"
|
||||
POPUPS_SIEVE_SCRIPT:
|
||||
TITLE_CREATE: "Create Script"
|
||||
TITLE_EDIT: "Edit Script"
|
||||
SCRIPT_NAME: "Name"
|
||||
BUTTON_ADD_FILTER: "Add a Filter"
|
||||
BUTTON_RAW_SCRIPT: "Use Custom User Script"
|
||||
BUTTON_SAVE: "Save"
|
||||
CAPABILITY_LABEL: "Capabilities"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "These changes need to be saved to the server."
|
||||
POPUPS_SYSTEM_FOLDERS:
|
||||
TITLE_SYSTEM_FOLDERS: "Select system folders"
|
||||
SELECT_CHOOSE_ONE: "Choose one"
|
||||
|
@ -431,21 +440,15 @@ en:
|
|||
BUTTON_BACK: "Back"
|
||||
SETTINGS_FILTERS:
|
||||
LEGEND_FILTERS: "Filters"
|
||||
LEGEND_SIEVE_SCRIPT: "Sieve Script"
|
||||
BUTTON_SAVE: "Save"
|
||||
BUTTON_ADD_FILTER: "Add a Filter"
|
||||
BUTTON_DELETE: "Delete"
|
||||
BUTTON_RAW_SCRIPT: "Use Custom User Script"
|
||||
SUBNAME_NONE: "None"
|
||||
SUBNAME_MOVE_TO: "Move to \"%FOLDER%\""
|
||||
SUBNAME_FORWARD_TO: "Forward to \"%EMAIL%\""
|
||||
SUBNAME_REJECT: "Reject"
|
||||
SUBNAME_VACATION_MESSAGE: "Vacation message"
|
||||
SUBNAME_DISCARD: "Discard"
|
||||
CAPABILITY_LABEL: "Capability"
|
||||
LOADING_PROCESS: "Updating filter list"
|
||||
DELETING_ASK: "Are you sure?"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "These changes need to be saved to the server."
|
||||
SETTINGS_IDENTITY:
|
||||
LEGEND_IDENTITY: "Identity"
|
||||
LABEL_DISPLAY_NAME: "Name"
|
||||
|
|
|
@ -348,6 +348,15 @@ de_DE:
|
|||
VACATION_RECIPIENTS_LABEL: "Empfänger (durch Komma getrennt)"
|
||||
REJECT_MESSAGE_LABEL: "Ablehnnachricht"
|
||||
ALL_INCOMING_MESSAGES_DESC: "Alle eingehenden Nachrichten"
|
||||
POPUPS_SIEVE_SCRIPT:
|
||||
TITLE_CREATE: "Skript erstellen"
|
||||
TITLE_EDIT: "Skript bearbeiten"
|
||||
SCRIPT_NAME: "Name"
|
||||
BUTTON_ADD_FILTER: "Filter hinzufügen"
|
||||
BUTTON_RAW_SCRIPT: "Benutzerdefiniertes Skript verwenden"
|
||||
BUTTON_SAVE: "Speichern"
|
||||
CAPABILITY_LABEL: "Unterstützte Module"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "Die Änderungen müssen auf dem Server gespeichert werden."
|
||||
POPUPS_SYSTEM_FOLDERS:
|
||||
TITLE_SYSTEM_FOLDERS: "Wählen Sie die Systemordner aus"
|
||||
SELECT_CHOOSE_ONE: "Wählen Sie einen aus"
|
||||
|
@ -431,20 +440,15 @@ de_DE:
|
|||
BUTTON_BACK: "Zurück"
|
||||
SETTINGS_FILTERS:
|
||||
LEGEND_FILTERS: "Filter"
|
||||
BUTTON_SAVE: "Speichern"
|
||||
BUTTON_ADD_FILTER: "Filter hinzufügen"
|
||||
BUTTON_DELETE: "Löschen"
|
||||
BUTTON_RAW_SCRIPT: "Benutzerdefiniertes Skript verwenden"
|
||||
SUBNAME_NONE: "Keine"
|
||||
SUBNAME_MOVE_TO: "Verschieben nach \"%FOLDER%\""
|
||||
SUBNAME_FORWARD_TO: "Weiterleiten nach \"%EMAIL%\""
|
||||
SUBNAME_REJECT: "Ablehnen"
|
||||
SUBNAME_VACATION_MESSAGE: "Urlaubsbenachrichtigung"
|
||||
SUBNAME_DISCARD: "Verwerfen"
|
||||
CAPABILITY_LABEL: "Unterstützte Module"
|
||||
LOADING_PROCESS: "Aktualisiere Filterliste"
|
||||
DELETING_ASK: "Sind Sie sicher?"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "Die Änderungen müssen auf dem Server gespeichert werden."
|
||||
SETTINGS_IDENTITY:
|
||||
LEGEND_IDENTITY: "Identität"
|
||||
LABEL_DISPLAY_NAME: "Name"
|
||||
|
|
|
@ -349,6 +349,15 @@ en_GB:
|
|||
VACATION_RECIPIENTS_LABEL: "Recipients (comma separated)"
|
||||
REJECT_MESSAGE_LABEL: "Reject message"
|
||||
ALL_INCOMING_MESSAGES_DESC: "All incoming messages"
|
||||
POPUPS_SIEVE_SCRIPT:
|
||||
TITLE_CREATE: "Create Script"
|
||||
TITLE_EDIT: "Edit Script"
|
||||
SCRIPT_NAME: "Name"
|
||||
BUTTON_ADD_FILTER: "Add a Filter"
|
||||
BUTTON_RAW_SCRIPT: "Use Custom User Script"
|
||||
BUTTON_SAVE: "Save"
|
||||
CAPABILITY_LABEL: "Capabilities"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "These changes need to be saved to the server."
|
||||
POPUPS_SYSTEM_FOLDERS:
|
||||
TITLE_SYSTEM_FOLDERS: "Select system folders"
|
||||
SELECT_CHOOSE_ONE: "Choose one"
|
||||
|
@ -431,20 +440,15 @@ en_GB:
|
|||
BUTTON_BACK: "Back"
|
||||
SETTINGS_FILTERS:
|
||||
LEGEND_FILTERS: "Filters"
|
||||
BUTTON_SAVE: "Save"
|
||||
BUTTON_ADD_FILTER: "Add a Filter"
|
||||
BUTTON_DELETE: "Delete"
|
||||
BUTTON_RAW_SCRIPT: "Use Custom User Script"
|
||||
SUBNAME_NONE: "None"
|
||||
SUBNAME_MOVE_TO: "Move to \"%FOLDER%\""
|
||||
SUBNAME_FORWARD_TO: "Forward to \"%EMAIL%\""
|
||||
SUBNAME_REJECT: "Reject"
|
||||
SUBNAME_VACATION_MESSAGE: "Vacation message"
|
||||
SUBNAME_DISCARD: "Discard"
|
||||
CAPABILITY_LABEL: "Capability"
|
||||
LOADING_PROCESS: "Updating filter list"
|
||||
DELETING_ASK: "Are you sure?"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "These changes need to be saved to the server."
|
||||
SETTINGS_IDENTITY:
|
||||
LEGEND_IDENTITY: "Identity"
|
||||
LABEL_DISPLAY_NAME: "Name"
|
||||
|
|
|
@ -349,6 +349,15 @@ en_US:
|
|||
VACATION_RECIPIENTS_LABEL: "Recipients (comma separated)"
|
||||
REJECT_MESSAGE_LABEL: "Reject message"
|
||||
ALL_INCOMING_MESSAGES_DESC: "All incoming messages"
|
||||
POPUPS_SIEVE_SCRIPT:
|
||||
TITLE_CREATE: "Create Script"
|
||||
TITLE_EDIT: "Edit Script"
|
||||
SCRIPT_NAME: "Name"
|
||||
BUTTON_ADD_FILTER: "Add a Filter"
|
||||
BUTTON_RAW_SCRIPT: "Use Custom User Script"
|
||||
BUTTON_SAVE: "Save"
|
||||
CAPABILITY_LABEL: "Capabilities"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "These changes need to be saved to the server."
|
||||
POPUPS_SYSTEM_FOLDERS:
|
||||
TITLE_SYSTEM_FOLDERS: "Select system folders"
|
||||
SELECT_CHOOSE_ONE: "Choose one"
|
||||
|
@ -431,20 +440,15 @@ en_US:
|
|||
BUTTON_BACK: "Back"
|
||||
SETTINGS_FILTERS:
|
||||
LEGEND_FILTERS: "Filters"
|
||||
BUTTON_SAVE: "Save"
|
||||
BUTTON_ADD_FILTER: "Add a Filter"
|
||||
BUTTON_DELETE: "Delete"
|
||||
BUTTON_RAW_SCRIPT: "Use Custom User Script"
|
||||
SUBNAME_NONE: "None"
|
||||
SUBNAME_MOVE_TO: "Move to \"%FOLDER%\""
|
||||
SUBNAME_FORWARD_TO: "Forward to \"%EMAIL%\""
|
||||
SUBNAME_REJECT: "Reject"
|
||||
SUBNAME_VACATION_MESSAGE: "Vacation message"
|
||||
SUBNAME_DISCARD: "Discard"
|
||||
CAPABILITY_LABEL: "Capability"
|
||||
LOADING_PROCESS: "Updating filter list"
|
||||
DELETING_ASK: "Are you sure?"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "These changes need to be saved to the server."
|
||||
SETTINGS_IDENTITY:
|
||||
LEGEND_IDENTITY: "Identity"
|
||||
LABEL_DISPLAY_NAME: "Name"
|
||||
|
|
|
@ -348,6 +348,15 @@ es_ES:
|
|||
VACATION_RECIPIENTS_LABEL: "Destinatarios (separados por coma)"
|
||||
REJECT_MESSAGE_LABEL: "Rechazar mensaje"
|
||||
ALL_INCOMING_MESSAGES_DESC: "Todos los mensajes entrantes"
|
||||
POPUPS_SIEVE_SCRIPT:
|
||||
TITLE_CREATE: "Create Script"
|
||||
TITLE_EDIT: "Edit Script"
|
||||
SCRIPT_NAME: "Nombre"
|
||||
BUTTON_ADD_FILTER: "Añadir un Filtro"
|
||||
BUTTON_RAW_SCRIPT: "Usar Script Personalizado"
|
||||
BUTTON_SAVE: "Guardar"
|
||||
CAPABILITY_LABEL: "Capability"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "Estos cambios deben ser cambiados en el servidor."
|
||||
POPUPS_SYSTEM_FOLDERS:
|
||||
TITLE_SYSTEM_FOLDERS: "Seleccione las carpetas del sistema"
|
||||
SELECT_CHOOSE_ONE: "Elija una"
|
||||
|
@ -432,20 +441,15 @@ es_ES:
|
|||
BUTTON_BACK: "Atrás"
|
||||
SETTINGS_FILTERS:
|
||||
LEGEND_FILTERS: "Filtros"
|
||||
BUTTON_SAVE: "Guardar"
|
||||
BUTTON_ADD_FILTER: "Añadir un Filtro"
|
||||
BUTTON_DELETE: "Borrar"
|
||||
BUTTON_RAW_SCRIPT: "Usar Script Personalizado"
|
||||
SUBNAME_NONE: "Ninguno"
|
||||
SUBNAME_MOVE_TO: "Mover a \"%FOLDER%\""
|
||||
SUBNAME_FORWARD_TO: "Reenviar a \"%EMAIL%\""
|
||||
SUBNAME_REJECT: "Rechazar"
|
||||
SUBNAME_VACATION_MESSAGE: "Mensaje de vacaciones"
|
||||
SUBNAME_DISCARD: "Descartar"
|
||||
CAPABILITY_LABEL: "Capability"
|
||||
LOADING_PROCESS: "Actualizando lista de filtros"
|
||||
DELETING_ASK: "¿Está seguro?"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "Estos cambios deben ser cambiados en el servidor."
|
||||
SETTINGS_IDENTITY:
|
||||
LEGEND_IDENTITY: "Identidad"
|
||||
LABEL_DISPLAY_NAME: "Nombre"
|
||||
|
|
|
@ -349,6 +349,15 @@ fr_FR:
|
|||
VACATION_RECIPIENTS_LABEL: "Destinataires (séparés par des virgules)"
|
||||
REJECT_MESSAGE_LABEL: "Message rejeté"
|
||||
ALL_INCOMING_MESSAGES_DESC: "Tous les messages entrants"
|
||||
POPUPS_SIEVE_SCRIPT:
|
||||
TITLE_CREATE: "Create Script"
|
||||
TITLE_EDIT: "Edit Script"
|
||||
SCRIPT_NAME: "Nom"
|
||||
BUTTON_ADD_FILTER: "Ajouter un filtre"
|
||||
BUTTON_RAW_SCRIPT: "Utiliser le script d'un utilisateur"
|
||||
BUTTON_SAVE: "Enregistrer"
|
||||
CAPABILITY_LABEL: "Capacité"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "Ces changements doivent être enregistrés sur le serveur."
|
||||
POPUPS_SYSTEM_FOLDERS:
|
||||
TITLE_SYSTEM_FOLDERS: "Sélectionner les dossiers systèmes"
|
||||
SELECT_CHOOSE_ONE: "Faites un choix"
|
||||
|
@ -432,20 +441,15 @@ fr_FR:
|
|||
BUTTON_BACK: "Retour"
|
||||
SETTINGS_FILTERS:
|
||||
LEGEND_FILTERS: "Filtres"
|
||||
BUTTON_SAVE: "Enregistrer"
|
||||
BUTTON_ADD_FILTER: "Ajouter un filtre"
|
||||
BUTTON_DELETE: "Effacer"
|
||||
BUTTON_RAW_SCRIPT: "Utiliser le script d'un utilisateur"
|
||||
SUBNAME_NONE: "Aucun"
|
||||
SUBNAME_MOVE_TO: "Déplacer vers \"%FOLDER%\""
|
||||
SUBNAME_FORWARD_TO: "Faire suivre à \"%EMAIL%\""
|
||||
SUBNAME_REJECT: "Rejeter"
|
||||
SUBNAME_VACATION_MESSAGE: "Message d'absence"
|
||||
SUBNAME_DISCARD: "Exclure"
|
||||
CAPABILITY_LABEL: "Capacité"
|
||||
LOADING_PROCESS: "Mise à jour de la liste de filtres"
|
||||
DELETING_ASK: "Êtes-vous sûr ?"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "Ces changements doivent être enregistrés sur le serveur."
|
||||
SETTINGS_IDENTITY:
|
||||
LEGEND_IDENTITY: "Identité"
|
||||
LABEL_DISPLAY_NAME: "Nom"
|
||||
|
|
|
@ -348,6 +348,15 @@ nl_NL:
|
|||
VACATION_RECIPIENTS_LABEL: "Ontvangers (comma gescheiden)"
|
||||
REJECT_MESSAGE_LABEL: "Afwijsbericht"
|
||||
ALL_INCOMING_MESSAGES_DESC: "Alle inkomende berichten"
|
||||
POPUPS_SIEVE_SCRIPT:
|
||||
TITLE_CREATE: "Script toevoegen"
|
||||
TITLE_EDIT: "Script aanpassen"
|
||||
SCRIPT_NAME: "Naam"
|
||||
BUTTON_ADD_FILTER: "Filter toevoegen"
|
||||
BUTTON_RAW_SCRIPT: "Maak een custom script"
|
||||
BUTTON_SAVE: "Opslaan"
|
||||
CAPABILITY_LABEL: "Mogelijkheden"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "Wijzigingen moeten nog opgeslagen worden op de server."
|
||||
POPUPS_SYSTEM_FOLDERS:
|
||||
TITLE_SYSTEM_FOLDERS: "Selecteer systeem mappen"
|
||||
SELECT_CHOOSE_ONE: "Kies één"
|
||||
|
@ -430,20 +439,15 @@ nl_NL:
|
|||
BUTTON_BACK: "Terug"
|
||||
SETTINGS_FILTERS:
|
||||
LEGEND_FILTERS: "Filters"
|
||||
BUTTON_SAVE: "Opslaan"
|
||||
BUTTON_ADD_FILTER: "Filter toevoegen"
|
||||
BUTTON_DELETE: "Verwijder"
|
||||
BUTTON_RAW_SCRIPT: "Maak een custom script"
|
||||
SUBNAME_NONE: "Geen"
|
||||
SUBNAME_MOVE_TO: "Verplaats naar map \"%FOLDER%\""
|
||||
SUBNAME_FORWARD_TO: "Doorsturen naar \"%EMAIL%\""
|
||||
SUBNAME_REJECT: "Afwijzen"
|
||||
SUBNAME_VACATION_MESSAGE: "Afwezigheidsbericht"
|
||||
SUBNAME_DISCARD: "Gooi weg"
|
||||
CAPABILITY_LABEL: "Mogelijkheden"
|
||||
LOADING_PROCESS: "Bezig met updaten van de filter lijst"
|
||||
DELETING_ASK: "Weet u het zeker?"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "Wijzigingen moeten nog opgeslagen worden op de server."
|
||||
SETTINGS_IDENTITY:
|
||||
LEGEND_IDENTITY: "Identiteit"
|
||||
LABEL_DISPLAY_NAME: "Naam"
|
||||
|
|
|
@ -348,6 +348,15 @@ zh_CN:
|
|||
VACATION_RECIPIENTS_LABEL: "收件人 (半角逗号“,”分隔)"
|
||||
REJECT_MESSAGE_LABEL: "拒收邮件"
|
||||
ALL_INCOMING_MESSAGES_DESC: "所有来信"
|
||||
POPUPS_SIEVE_SCRIPT:
|
||||
TITLE_CREATE: "Create Script"
|
||||
TITLE_EDIT: "Edit Script"
|
||||
SCRIPT_NAME: "名称"
|
||||
BUTTON_ADD_FILTER: "添加筛选条件"
|
||||
BUTTON_RAW_SCRIPT: "使用自定义脚本"
|
||||
BUTTON_SAVE: "保存"
|
||||
CAPABILITY_LABEL: "Capability"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "这些更改需要保存。"
|
||||
POPUPS_SYSTEM_FOLDERS:
|
||||
TITLE_SYSTEM_FOLDERS: "选择系统文件夹"
|
||||
SELECT_CHOOSE_ONE: "选择一个"
|
||||
|
@ -429,20 +438,15 @@ zh_CN:
|
|||
BUTTON_BACK: "返回"
|
||||
SETTINGS_FILTERS:
|
||||
LEGEND_FILTERS: "筛选器"
|
||||
BUTTON_SAVE: "保存"
|
||||
BUTTON_ADD_FILTER: "添加筛选条件"
|
||||
BUTTON_DELETE: "删除"
|
||||
BUTTON_RAW_SCRIPT: "使用自定义脚本"
|
||||
SUBNAME_NONE: "无"
|
||||
SUBNAME_MOVE_TO: "移动到 \"%FOLDER%\""
|
||||
SUBNAME_FORWARD_TO: "转发到 \"%EMAIL%\""
|
||||
SUBNAME_REJECT: "拒绝"
|
||||
SUBNAME_VACATION_MESSAGE: "假期自动回复"
|
||||
SUBNAME_DISCARD: "取消"
|
||||
CAPABILITY_LABEL: "Capability"
|
||||
LOADING_PROCESS: "正在更新筛选规则列表"
|
||||
DELETING_ASK: "确定删除?"
|
||||
CHANGES_NEED_TO_BE_SAVED_DESC: "这些更改需要保存。"
|
||||
SETTINGS_IDENTITY:
|
||||
LEGEND_IDENTITY: "身份"
|
||||
LABEL_DISPLAY_NAME: "名称"
|
||||
|
|
|
@ -1,51 +1,65 @@
|
|||
<div class="modal fade b-filter-script g-ui-user-select-none" data-bind="modal: modalVisibility">
|
||||
<div>
|
||||
<div data-bind="with: script">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-bind="command: cancelCommand">×</button>
|
||||
<h3 class="i18n" data-i18n="POPUPS_FILTER/LEGEND_SIEVE_SCRIPT"></h3>
|
||||
<button type="button" class="close" data-bind="command: $root.cancelCommand">×</button>
|
||||
<h3>
|
||||
<span class="i18n" data-i18n="POPUPS_SIEVE_SCRIPT/TITLE_CREATE" data-bind="visible: $root.isNew"></span>
|
||||
<span class="i18n" data-i18n="POPUPS_SIEVE_SCRIPT/TITLE_EDIT" data-bind="visible: !$root.isNew()"></span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row" data-bind="visible: haveChanges">
|
||||
|
||||
<div class="control-group" data-bind="css: {'error': nameError}">
|
||||
<div class="controls">
|
||||
<input type="text" class="i18n span5"
|
||||
data-bind="value: name, hasFocus: $root.isNew, visible: $root.isNew"
|
||||
autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
data-i18n="[placeholder]POPUPS_SIEVE_SCRIPT/SCRIPT_NAME"
|
||||
/>
|
||||
<span data-bind="text: name, visible: !$root.isNew()"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" data-bind="visible: hasChanges">
|
||||
<div class="span8 width100-on-mobile">
|
||||
<br />
|
||||
<div class="alert g-ui-user-select-none" style="margin-bottom: 0">
|
||||
<div class="alert g-ui-user-select-none">
|
||||
<i class="icon-warning"></i>
|
||||
|
||||
<span class="i18n" data-i18n="SETTINGS_FILTERS/CHANGES_NEED_TO_BE_SAVED_DESC"></span>
|
||||
<span class="i18n" data-i18n="POPUPS_SIEVE_SCRIPT/CHANGES_NEED_TO_BE_SAVED_DESC"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" data-bind="visible: serverError">
|
||||
<div class="row" data-bind="visible: $root.saveError">
|
||||
<div class="span8 width100-on-mobile">
|
||||
<div class="alert alert-error g-ui-user-select-none" style="margin-bottom: 0">
|
||||
<div class="alert alert-error g-ui-user-select-none">
|
||||
<i class="icon-warning"></i>
|
||||
|
||||
<span data-bind="text: serverErrorDesc"></span>
|
||||
<span data-bind="text: $root.saveErrorText"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="row">
|
||||
<!--
|
||||
<div class="row" data-bind="visible: allowFilters">
|
||||
<div class="span5 width100-on-mobile">
|
||||
<a class="btn" data-bind="click: function () { filterRaw.active(!filterRaw.active()) },
|
||||
css: {'active': filterRaw.active }, tooltip: 'SETTINGS_FILTERS/BUTTON_RAW_SCRIPT'">
|
||||
<a class="btn" data-bind="click: function () { $root.rawActive(!$root.rawActive()) },
|
||||
css: {'active': $root.rawActive }, tooltip: 'POPUPS_SIEVE_SCRIPT/BUTTON_RAW_SCRIPT'">
|
||||
<i class="icon-file-code"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
<div class="row">
|
||||
<div class="span8 width100-on-mobile">
|
||||
<div class="control-group" data-bind="css: {'error': filterRaw.error}, visible: filterRaw.active()">
|
||||
<div class="control-group" data-bind="visible: $root.rawActive">
|
||||
<div class="controls">
|
||||
<pre style="word-break: break-word;" data-bind="visible: '' !== filterRaw.capa()">
|
||||
<b class="i18n" data-i18n="SETTINGS_FILTERS/CAPABILITY_LABEL"></b>:
|
||||
<span data-bind="text: filterRaw.capa"></span>
|
||||
<pre>
|
||||
<b class="i18n" data-i18n="POPUPS_SIEVE_SCRIPT/CAPABILITY_LABEL"></b>:
|
||||
<span data-bind="text: $root.sieveCapabilities"></span>
|
||||
</pre>
|
||||
<textarea class="span8" style="height: 300px; font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;"
|
||||
data-bind="value: filterRaw, valueUpdate: 'afterkeydown'"></textarea>
|
||||
<textarea class="span8" data-bind="value: body, valueUpdate: 'afterkeydown'"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div data-bind="visible: !filterRaw.active()">
|
||||
<div data-bind="visible: !$root.rawActive()">
|
||||
<table class="table table-hover list-table filters-list g-ui-user-select-none"
|
||||
data-bind="i18nUpdate: filters">
|
||||
<colgroup>
|
||||
|
@ -55,10 +69,10 @@
|
|||
<col style="width: 140px" />
|
||||
<col style="width: 1%" />
|
||||
</colgroup>
|
||||
<tbody data-bind="foreach: filters" style="width: 600px">
|
||||
<tbody data-bind="foreach: filters">
|
||||
<tr class="filter-item" draggable="true" data-bind="sortableItem: { list: $root.filters }">
|
||||
<td>
|
||||
<span class="disabled-filter" data-bind="click: function () { $root.haveChanges(true); enabled(!enabled()); }">
|
||||
<span class="disabled-filter" data-bind="click: function () { $parent.hasChanges(true); enabled(!enabled()); }">
|
||||
<i data-bind="css: {'icon-checkbox-checked': enabled, 'icon-checkbox-unchecked': !enabled()}"></i>
|
||||
</span>
|
||||
</td>
|
||||
|
@ -83,20 +97,20 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<a class="btn" data-bind="click: addFilter">
|
||||
<a class="btn" data-bind="click: $root.addFilter">
|
||||
<i class="icon-plus"></i>
|
||||
|
||||
<span class="i18n" data-i18n="SETTINGS_FILTERS/BUTTON_ADD_FILTER"></span>
|
||||
<span class="i18n" data-i18n="POPUPS_SIEVE_SCRIPT/BUTTON_ADD_FILTER"></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="btn buttonSave" data-bind="command: saveScriptCommand, tooltipErrorTip: saveErrorText, css: {'btn-danger': '' !== saveErrorText()}">
|
||||
<i data-bind="css: {'icon-floppy': !script.saving(), 'icon-spinner animated': script.saving()}"></i>
|
||||
<a class="btn buttonSave" data-bind="visible: hasChanges, click: function() { $root.saveScriptCommand(); }, css: {'btn-danger': $root.saveError}">
|
||||
<i data-bind="css: {'icon-floppy': !$root.saving, 'icon-spinner animated': $root.saving}"></i>
|
||||
|
||||
<span class="i18n" data-i18n="SETTINGS_FILTERS/BUTTON_SAVE"></span>
|
||||
<span class="i18n" data-i18n="POPUPS_SIEVE_SCRIPT/BUTTON_SAVE"></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="legend">
|
||||
<span class="i18n" data-i18n="SETTINGS_FILTERS/LEGEND_FILTERS"></span>
|
||||
|
||||
<i class="icon-spinner animated" style="margin-top: 5px" data-bind="visible: filters.loading"></i>
|
||||
<i class="icon-spinner animated" style="margin-top: 5px" data-bind="visible: loading"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" data-bind="visible: serverError">
|
||||
|
|
Loading…
Reference in a new issue