mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-29 03:59:21 +03: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 };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue