Merge branch 'master' into UserMailTemplates

# Conflicts:
#	dev/App/User.js
#	dev/Common/Enums.js
#	dev/Screen/User/Settings.js
#	dev/Settings/Admin/General.js
#	snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php
#	snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Admin.php
#	snappymail/v/0.0.0/app/libraries/RainLoop/Actions/User.php
This commit is contained in:
djmaze 2022-03-15 15:00:14 +01:00
commit f7f56b3789
794 changed files with 96444 additions and 74188 deletions

View file

@ -1,7 +1,6 @@
import ko from 'ko';
import { Capa } from 'Common/Enums';
import { Settings } from 'Common/Globals';
import { SettingsCapa, SettingsGet } from 'Common/Globals';
import { AccountUserStore } from 'Stores/User/Account';
import { IdentityUserStore } from 'Stores/User/Identity';
@ -12,17 +11,18 @@ import { showScreenPopup } from 'Knoin/Knoin';
import { AccountPopupView } from 'View/Popup/Account';
import { IdentityPopupView } from 'View/Popup/Identity';
export class AccountsUserSettings {
export class UserSettingsAccounts /*extends AbstractViewSettings*/ {
constructor() {
this.allowAdditionalAccount = Settings.capa(Capa.AdditionalAccounts);
this.allowIdentities = Settings.capa(Capa.Identities);
this.allowAdditionalAccount = SettingsCapa('AdditionalAccounts');
this.allowIdentities = SettingsCapa('Identities');
this.accounts = AccountUserStore.accounts;
this.loading = AccountUserStore.loading;
this.identities = IdentityUserStore;
this.mainEmail = SettingsGet('MainEmail');
this.accountForDeletion = ko.observable(null).deleteAccessHelper();
this.identityForDeletion = ko.observable(null).deleteAccessHelper();
this.accountForDeletion = ko.observable(null).askDeleteHelper();
this.identityForDeletion = ko.observable(null).askDeleteHelper();
}
addNewAccount() {
@ -30,7 +30,7 @@ export class AccountsUserSettings {
}
editAccount(account) {
if (account && account.canBeEdit()) {
if (account && account.isAdditional()) {
showScreenPopup(AccountPopupView, [account]);
}
}
@ -48,19 +48,21 @@ export class AccountsUserSettings {
* @returns {void}
*/
deleteAccount(accountToRemove) {
if (accountToRemove && accountToRemove.deleteAccess()) {
if (accountToRemove && accountToRemove.askDelete()) {
this.accountForDeletion(null);
if (accountToRemove) {
this.accounts.remove((account) => accountToRemove === account);
Remote.accountDelete((iError, data) => {
Remote.request('AccountDelete', (iError, data) => {
if (!iError && data.Reload) {
rl.route.root();
setTimeout(() => location.reload(), 1);
} else {
rl.app.accountsAndIdentities();
}
}, accountToRemove.email);
}, {
EmailToDelete: accountToRemove.email
});
}
}
}
@ -70,18 +72,23 @@ export class AccountsUserSettings {
* @returns {void}
*/
deleteIdentity(identityToRemove) {
if (identityToRemove && identityToRemove.deleteAccess()) {
if (identityToRemove && identityToRemove.askDelete()) {
this.identityForDeletion(null);
if (identityToRemove) {
IdentityUserStore.remove(oIdentity => identityToRemove === oIdentity);
Remote.identityDelete(() => rl.app.accountsAndIdentities(), identityToRemove.id());
Remote.request('IdentityDelete', () => rl.app.accountsAndIdentities(), {
IdToDelete: identityToRemove.id()
});
}
}
}
accountsAndIdentitiesAfterMove() {
Remote.accountsAndIdentitiesSortOrder(null, AccountUserStore.getEmailAddresses(), IdentityUserStore.getIDS());
Remote.request('AccountsAndIdentitiesSortOrder', null, {
Accounts: AccountUserStore.getEmailAddresses().filter(v => v != SettingsGet('MainEmail')),
Identities: IdentityUserStore.getIDS()
});
}
onBuild(oDom) {

View file

@ -1,10 +1,11 @@
import ko from 'ko';
import { koComputable } from 'External/ko';
import { SettingsGet } from 'Common/Globals';
import { ContactUserStore } from 'Stores/User/Contact';
import Remote from 'Remote/User/Fetch';
export class ContactsUserSettings {
export class UserSettingsContacts /*extends AbstractViewSettings*/ {
constructor() {
this.contactsAutosave = ko.observable(!!SettingsGet('ContactsAutosave'));
@ -14,8 +15,7 @@ export class ContactsUserSettings {
this.contactsSyncUser = ContactUserStore.syncUser;
this.contactsSyncPass = ContactUserStore.syncPass;
this.saveTrigger = ko
.computed(() =>
this.saveTrigger = koComputable(() =>
[
ContactUserStore.enableSync() ? '1' : '0',
ContactUserStore.syncUrl(),
@ -26,19 +26,16 @@ export class ContactsUserSettings {
.extend({ debounce: 500 });
this.contactsAutosave.subscribe(value =>
Remote.saveSettings(null, {
ContactsAutosave: value ? 1 : 0
})
Remote.saveSettings(null, { ContactsAutosave: value })
);
this.saveTrigger.subscribe(() =>
Remote.saveContactsSyncData(
null,
ContactUserStore.enableSync(),
ContactUserStore.syncUrl(),
ContactUserStore.syncUser(),
ContactUserStore.syncPass()
)
Remote.request('SaveContactsSyncData', null, {
Enable: ContactUserStore.enableSync() ? 1 : 0,
Url: ContactUserStore.syncUrl(),
User: ContactUserStore.syncUser(),
Password: ContactUserStore.syncPass()
})
);
}
}

View file

@ -1,100 +1,44 @@
import ko from 'ko';
import { addObservablesTo } from 'External/ko';
import { FolderUserStore } from 'Stores/User/Folder';
import { SettingsGet } from 'Common/Globals';
import { getNotification } from 'Common/Translator';
import { addObservablesTo } from 'Common/Utils';
import { delegateRunOnDestroy } from 'Common/UtilsUser';
import { SieveUserStore } from 'Stores/User/Sieve';
import Remote from 'Remote/User/Fetch';
import { SieveScriptModel } from 'Model/SieveScript';
import { showScreenPopup } from 'Knoin/Knoin';
import { SieveScriptPopupView } from 'View/Popup/SieveScript';
export class FiltersUserSettings {
//export class UserSettingsFilters /*extends AbstractViewSettings*/ {
export class UserSettingsFilters /*extends AbstractViewSettings*/ {
constructor() {
this.scripts = SieveUserStore.scripts;
this.loading = ko.observable(false).extend({ debounce: 200 });
this.scripts = ko.observableArray();
this.loading = ko.observable(true).extend({ debounce: 200 });
addObservablesTo(this, {
serverError: false,
serverErrorDesc: ''
});
this.scriptForDeletion = ko.observable(null).deleteAccessHelper();
}
rl.loadScript(SettingsGet('StaticLibsJs').replace('/libs.', '/sieve.')).then(() => {
const Sieve = window.Sieve;
Sieve.folderList = FolderUserStore.folderList;
Sieve.serverError.subscribe(value => this.serverError(value));
Sieve.serverErrorDesc.subscribe(value => this.serverErrorDesc(value));
Sieve.loading.subscribe(value => this.loading(value));
Sieve.scripts.subscribe(value => this.scripts(value));
Sieve.updateList();
}).catch(e => console.error(e));
setError(text) {
this.serverError(true);
this.serverErrorDesc(text);
}
updateList() {
if (!this.loading()) {
this.loading(true);
this.serverError(false);
Remote.filtersGet((iError, data) => {
this.loading(false);
this.scripts([]);
if (iError) {
SieveUserStore.capa([]);
this.setError(getNotification(iError));
} else {
SieveUserStore.capa(data.Result.Capa);
/*
this.scripts(
data.Result.Scripts.map(aItem => SieveScriptModel.reviveFromJson(aItem)).filter(v => v)
);
*/
Object.values(data.Result.Scripts).forEach(value => {
value = SieveScriptModel.reviveFromJson(value);
value && this.scripts.push(value)
});
}
});
}
this.scriptForDeletion = ko.observable(null).askDeleteHelper();
}
addScript() {
showScreenPopup(SieveScriptPopupView, [new SieveScriptModel()]);
this.editScript();
}
editScript(script) {
showScreenPopup(SieveScriptPopupView, [script]);
window.Sieve.ScriptView.showModal(script ? [script] : null);
}
deleteScript(script) {
this.serverError(false);
Remote.filtersScriptDelete(
(iError, data) => {
if (iError) {
this.setError((data && data.ErrorMessageAdditional) || getNotification(iError));
} else {
this.scripts.remove(script);
delegateRunOnDestroy(script);
}
},
script.name()
);
window.Sieve.deleteScript(script);
}
toggleScript(script) {
let name = script.active() ? '' : script.name();
this.serverError(false);
Remote.filtersScriptActivate(
(iError, data) => {
if (iError) {
this.setError((data && data.ErrorMessageAdditional) || iError)
} else {
this.scripts.forEach(script => script.active(script.name() === name));
}
},
name
);
window.Sieve.toggleScript(script);
}
onBuild(oDom) {
@ -106,6 +50,6 @@ export class FiltersUserSettings {
}
onShow() {
this.updateList();
window.Sieve && window.Sieve.updateList();
}
}

View file

@ -1,13 +1,15 @@
import ko from 'ko';
import { koComputable } from 'External/ko';
import { Notification } from 'Common/Enums';
import { ClientSideKeyName } from 'Common/EnumsUser';
import { Settings } from 'Common/Globals';
import { FolderMetadataKeys } from 'Common/EnumsUser';
import { SettingsCapa } from 'Common/Globals';
import { getNotification } from 'Common/Translator';
import { removeFolderFromCacheList } from 'Common/Cache';
import * as Local from 'Storage/Client';
import { setFolder, getFolderFromCacheList, removeFolderFromCacheList } from 'Common/Cache';
import { defaultOptionsAfterRender } from 'Common/Utils';
import { sortFolders } from 'Common/Folders';
import { initOnStartOrLangChange, i18n } from 'Common/Translator';
import { FolderUserStore } from 'Stores/User/Folder';
import { SettingsUserStore } from 'Stores/User/Settings';
@ -18,16 +20,36 @@ import { showScreenPopup } from 'Knoin/Knoin';
import { FolderCreatePopupView } from 'View/Popup/FolderCreate';
import { FolderSystemPopupView } from 'View/Popup/FolderSystem';
import { loadFolders } from 'Model/FolderCollection';
export class FoldersUserSettings {
const folderForDeletion = ko.observable(null).askDeleteHelper();
export class UserSettingsFolders /*extends AbstractViewSettings*/ {
constructor() {
this.showKolab = koComputable(() => FolderUserStore.hasCapability('METADATA') && SettingsCapa('Kolab'));
this.defaultOptionsAfterRender = defaultOptionsAfterRender;
this.kolabTypeOptions = ko.observableArray();
let i18nFilter = key => i18n('SETTINGS_FOLDERS/TYPE_' + key);
initOnStartOrLangChange(()=>{
this.kolabTypeOptions([
{ id: '', name: '' },
{ id: 'event', name: i18nFilter('CALENDAR') },
{ id: 'contact', name: i18nFilter('CONTACTS') },
{ id: 'task', name: i18nFilter('TASKS') },
{ id: 'note', name: i18nFilter('NOTES') },
{ id: 'file', name: i18nFilter('FILES') },
{ id: 'journal', name: i18nFilter('JOURNAL') },
{ id: 'configuration', name: i18nFilter('CONFIGURATION') }
]);
});
this.displaySpecSetting = FolderUserStore.displaySpecSetting;
this.folderList = FolderUserStore.folderList;
this.folderListOptimized = FolderUserStore.folderListOptimized;
this.folderListError = FolderUserStore.folderListError;
this.hideUnsubscribed = SettingsUserStore.hideUnsubscribed;
this.loading = ko.computed(() => {
this.loading = koComputable(() => {
const loading = FolderUserStore.foldersLoading(),
creating = FolderUserStore.foldersCreating(),
deleting = FolderUserStore.foldersDeleting(),
@ -36,28 +58,43 @@ export class FoldersUserSettings {
return loading || creating || deleting || renaming;
});
this.folderForDeletion = ko.observable(null).deleteAccessHelper();
this.folderForDeletion = folderForDeletion;
this.folderForEdit = ko.observable(null).extend({ toggleSubscribeProperty: [this, 'edited'] });
this.useImapSubscribe = Settings.app('useImapSubscribe');
SettingsUserStore.hideUnsubscribed.subscribe(value => Remote.saveSetting('HideUnsubscribed', value ? 1 : 0));
SettingsUserStore.hideUnsubscribed.subscribe(value => Remote.saveSetting('HideUnsubscribed', value));
}
folderEditOnEnter(folder) {
const nameToEdit = folder ? folder.nameForEdit().trim() : '';
if (nameToEdit && folder.name() !== nameToEdit) {
Local.set(ClientSideKeyName.FoldersLashHash, '');
rl.app.foldersPromisesActionHelper(
Remote.folderRename(folder.fullNameRaw, nameToEdit),
Notification.CantRenameFolder
);
removeFolderFromCacheList(folder.fullNameRaw);
folder.name(nameToEdit);
Remote.abort('Folders').post('FolderRename', FolderUserStore.foldersRenaming, {
Folder: folder.fullName,
NewFolderName: nameToEdit,
Subscribe: folder.subscribed() ? 1 : 0
})
.then(data => {
folder.name(nameToEdit/*data.Name*/);
if (folder.subFolders.length) {
Remote.setTrigger(FolderUserStore.foldersLoading, true);
// clearTimeout(Remote.foldersTimeout);
// Remote.foldersTimeout = setTimeout(loadFolders, 500);
setTimeout(loadFolders, 500);
// TODO: rename all subfolders with folder.delimiter to prevent reload?
} else {
removeFolderFromCacheList(folder.fullName);
folder.fullName = data.Result.FullName;
setFolder(folder);
const parent = getFolderFromCacheList(folder.parentName);
sortFolders(parent ? parent.subFolders : FolderUserStore.folderList);
}
})
.catch(error => {
FolderUserStore.folderListError(
getNotification(error.code, '', Notification.CantRenameFolder)
+ '.\n' + error.message);
});
}
folder.edited(false);
@ -85,48 +122,69 @@ export class FoldersUserSettings {
}
deleteFolder(folderToRemove) {
if (
folderToRemove &&
folderToRemove.canBeDeleted() &&
folderToRemove.deleteAccess() &&
0 === folderToRemove.privateMessageCountAll()
if (folderToRemove
&& folderToRemove.canBeDeleted()
&& folderToRemove.askDelete()
) {
this.folderForDeletion(null);
if (0 < folderToRemove.privateMessageCountAll()) {
// FolderUserStore.folderListError(getNotification(Notification.CantDeleteNonEmptyFolder));
folderToRemove.errorMsg(getNotification(Notification.CantDeleteNonEmptyFolder));
} else {
folderForDeletion(null);
if (folderToRemove) {
Local.set(ClientSideKeyName.FoldersLashHash, '');
// rl.app.foldersPromisesActionHelper
Remote.abort('Folders')
.folderDelete(folderToRemove.fullNameRaw)
.then(
() => {
folderToRemove.selectable(false)
removeFolderFromCacheList(folderToRemove.fullNameRaw);
},
error => {
FolderUserStore.folderListError(
getNotification(error.code, '', Notification.CantDeleteFolder)
+ '.\n' + error.message
);
}
);
if (folderToRemove) {
Remote.abort('Folders').post('FolderDelete', FolderUserStore.foldersDeleting, {
Folder: folderToRemove.fullName
}).then(
() => {
// folderToRemove.flags.push('\\nonexistent');
folderToRemove.selectable(false);
// folderToRemove.subscribed(false);
// folderToRemove.checkable(false);
if (!folderToRemove.subFolders.length) {
removeFolderFromCacheList(folderToRemove.fullName);
const folder = getFolderFromCacheList(folderToRemove.parentName);
(folder ? folder.subFolders : FolderUserStore.folderList).remove(folderToRemove);
}
},
error => {
FolderUserStore.folderListError(
getNotification(error.code, '', Notification.CantDeleteFolder)
+ '.\n' + error.message
);
}
);
}
}
} else if (0 < folderToRemove.privateMessageCountAll()) {
FolderUserStore.folderListError(getNotification(Notification.CantDeleteNonEmptyFolder));
}
}
toggleFolderKolabType(folder, event) {
let type = event.target.value;
// TODO: append '.default' ?
Remote.request('FolderSetMetadata', null, {
Folder: folder.fullName,
Key: FolderMetadataKeys.KolabFolderType,
Value: type
});
folder.kolabType(type);
}
toggleFolderSubscription(folder) {
let subscribe = !folder.subscribed();
Local.set(ClientSideKeyName.FoldersLashHash, '');
Remote.folderSetSubscribe(()=>0, folder.fullNameRaw, subscribe);
Remote.request('FolderSubscribe', null, {
Folder: folder.fullName,
Subscribe: subscribe ? 1 : 0
});
folder.subscribed(subscribe);
}
toggleFolderCheckable(folder) {
let checkable = !folder.checkable();
Remote.folderSetCheckable(()=>0, folder.fullNameRaw, checkable);
Remote.request('FolderCheckable', null, {
Folder: folder.fullName,
Checkable: checkable ? 1 : 0
});
folder.checkable(checkable);
}
}

View file

@ -3,9 +3,11 @@ import ko from 'ko';
import { SaveSettingsStep } from 'Common/Enums';
import { EditorDefaultType, Layout } from 'Common/EnumsUser';
import { Settings, SettingsGet } from 'Common/Globals';
import { isArray, settingsSaveHelperSimpleFunction, addObservablesTo, addSubscribablesTo, addComputablesTo } from 'Common/Utils';
import { i18n, trigger as translatorTrigger, reload as translatorReload, convertLangName } from 'Common/Translator';
import { isArray } from 'Common/Utils';
import { addSubscribablesTo, addComputablesTo } from 'External/ko';
import { i18n, trigger as translatorTrigger, translatorReload, convertLangName } from 'Common/Translator';
import { AbstractViewSettings } from 'Knoin/AbstractViews';
import { showScreenPopup } from 'Knoin/Knoin';
import { AppUserStore } from 'Stores/User/App';
@ -14,14 +16,17 @@ import { SettingsUserStore } from 'Stores/User/Settings';
import { IdentityUserStore } from 'Stores/User/Identity';
import { NotificationUserStore } from 'Stores/User/Notification';
import { MessageUserStore } from 'Stores/User/Message';
import { MessagelistUserStore } from 'Stores/User/Messagelist';
import Remote from 'Remote/User/Fetch';
import { IdentityPopupView } from 'View/Popup/Identity';
import { LanguagesPopupView } from 'View/Popup/Languages';
export class GeneralUserSettings {
export class UserSettingsGeneral extends AbstractViewSettings {
constructor() {
super();
this.language = LanguageStore.language;
this.languages = LanguageStore.languages;
this.messageReadDelay = SettingsUserStore.messageReadDelay;
@ -30,13 +35,14 @@ export class GeneralUserSettings {
this.editorDefaultType = SettingsUserStore.editorDefaultType;
this.layout = SettingsUserStore.layout;
this.enableSoundNotification = NotificationUserStore.enableSoundNotification;
this.soundNotification = NotificationUserStore.enableSoundNotification;
this.notificationSound = ko.observable(SettingsGet('NotificationSound'));
this.notificationSounds = ko.observableArray(SettingsGet('NewMailSounds'));
this.enableDesktopNotification = NotificationUserStore.enableDesktopNotification;
this.desktopNotification = NotificationUserStore.enableDesktopNotification;
this.isDesktopNotificationAllowed = NotificationUserStore.isDesktopNotificationAllowed;
this.viewHTML = SettingsUserStore.viewHTML;
this.showImages = SettingsUserStore.showImages;
this.removeColors = SettingsUserStore.removeColors;
this.useCheckboxesInList = SettingsUserStore.useCheckboxesInList;
@ -45,14 +51,7 @@ export class GeneralUserSettings {
this.replySameFolder = SettingsUserStore.replySameFolder;
this.allowLanguagesOnSettings = !!SettingsGet('AllowLanguagesOnSettings');
this.languageTrigger = ko.observable(SaveSettingsStep.Idle).extend({ debounce: 100 });
addObservablesTo(this, {
mppTrigger: SaveSettingsStep.Idle,
messageReadDelayTrigger: SaveSettingsStep.Idle,
editorDefaultTypeTrigger: SaveSettingsStep.Idle,
layoutTrigger: SaveSettingsStep.Idle
});
this.languageTrigger = ko.observable(SaveSettingsStep.Idle);
this.identities = IdentityUserStore;
@ -89,58 +88,43 @@ export class GeneralUserSettings {
}
});
this.addSetting('EditorDefaultType');
this.addSetting('MessageReadDelay');
this.addSetting('MessagesPerPage');
this.addSetting('Layout', () => MessagelistUserStore([]));
this.addSettings(['ViewHTML', 'ShowImages', 'UseCheckboxesInList', 'ReplySameFolder',
'DesktopNotifications', 'SoundNotification']);
const fReloadLanguageHelper = (saveSettingsStep) => () => {
this.languageTrigger(saveSettingsStep);
setTimeout(() => this.languageTrigger(SaveSettingsStep.Idle), 1000);
};
addSubscribablesTo(this, {
language: value => {
this.languageTrigger(SaveSettingsStep.Animate);
translatorReload(false, value)
.then(fReloadLanguageHelper(SaveSettingsStep.TrueResult),
fReloadLanguageHelper(SaveSettingsStep.FalseResult))
.then(fReloadLanguageHelper(SaveSettingsStep.TrueResult), fReloadLanguageHelper(SaveSettingsStep.FalseResult))
.then(() => Remote.saveSetting('Language', value));
},
editorDefaultType: value => Remote.saveSetting('EditorDefaultType', value,
settingsSaveHelperSimpleFunction(this.editorDefaultTypeTrigger, this)),
messageReadDelay: value => Remote.saveSetting('MessageReadDelay', value,
settingsSaveHelperSimpleFunction(this.messageReadDelayTrigger, this)),
messagesPerPage: value => Remote.saveSetting('MPP', value,
settingsSaveHelperSimpleFunction(this.mppTrigger, this)),
showImages: value => Remote.saveSetting('ShowImages', value ? 1 : 0),
removeColors: value => {
let dom = MessageUserStore.messagesBodiesDom();
let dom = MessageUserStore.bodiesDom();
if (dom) {
dom.innerHTML = '';
}
Remote.saveSetting('RemoveColors', value ? 1 : 0);
Remote.saveSetting('RemoveColors', value);
},
useCheckboxesInList: value => Remote.saveSetting('UseCheckboxesInList', value ? 1 : 0),
enableDesktopNotification: value => Remote.saveSetting('DesktopNotifications', value ? 1 : 0),
enableSoundNotification: value => Remote.saveSetting('SoundNotification', value ? 1 : 0),
notificationSound: value => {
Remote.saveSetting('NotificationSound', value);
Settings.set('NotificationSound', value);
},
replySameFolder: value => Remote.saveSetting('ReplySameFolder', value ? 1 : 0),
useThreads: value => {
MessageUserStore.list([]);
Remote.saveSetting('UseThreads', value ? 1 : 0);
},
layout: value => {
MessageUserStore.list([]);
Remote.saveSetting('Layout', value, settingsSaveHelperSimpleFunction(this.layoutTrigger, this));
MessagelistUserStore([]);
Remote.saveSetting('UseThreads', value);
}
});
}

View file

@ -1,66 +0,0 @@
import ko from 'ko';
import { delegateRunOnDestroy } from 'Common/UtilsUser';
import { PgpUserStore } from 'Stores/User/Pgp';
import { SettingsUserStore } from 'Stores/User/Settings';
import Remote from 'Remote/User/Fetch';
import { showScreenPopup } from 'Knoin/Knoin';
import { AddOpenPgpKeyPopupView } from 'View/Popup/AddOpenPgpKey';
import { NewOpenPgpKeyPopupView } from 'View/Popup/NewOpenPgpKey';
import { ViewOpenPgpKeyPopupView } from 'View/Popup/ViewOpenPgpKey';
export class OpenPgpUserSettings {
constructor() {
this.openpgpkeys = PgpUserStore.openpgpkeys;
this.openpgpkeysPublic = PgpUserStore.openpgpkeysPublic;
this.openpgpkeysPrivate = PgpUserStore.openpgpkeysPrivate;
this.openPgpKeyForDeletion = ko.observable(null).deleteAccessHelper();
this.allowDraftAutosave = SettingsUserStore.allowDraftAutosave;
this.allowDraftAutosave.subscribe(value => Remote.saveSetting('AllowDraftAutosave', value ? 1 : 0))
}
addOpenPgpKey() {
showScreenPopup(AddOpenPgpKeyPopupView);
}
generateOpenPgpKey() {
showScreenPopup(NewOpenPgpKeyPopupView);
}
viewOpenPgpKey(openPgpKey) {
if (openPgpKey) {
showScreenPopup(ViewOpenPgpKeyPopupView, [openPgpKey]);
}
}
/**
* @param {OpenPgpKeyModel} openPgpKeyToRemove
* @returns {void}
*/
deleteOpenPgpKey(openPgpKeyToRemove) {
if (openPgpKeyToRemove && openPgpKeyToRemove.deleteAccess()) {
this.openPgpKeyForDeletion(null);
if (openPgpKeyToRemove && PgpUserStore.openpgpKeyring) {
const findedItem = PgpUserStore.openpgpkeys.find(key => openPgpKeyToRemove === key);
if (findedItem) {
PgpUserStore.openpgpkeys.remove(findedItem);
delegateRunOnDestroy(findedItem);
PgpUserStore.openpgpKeyring[findedItem.isPrivate ? 'privateKeys' : 'publicKeys'].removeForId(findedItem.guid);
PgpUserStore.openpgpKeyring.store();
}
rl.app.reloadOpenPgpKeys();
}
}
}
}

View file

@ -1,23 +1,32 @@
import ko from 'ko';
import { koComputable } from 'External/ko';
import { pInt, settingsSaveHelperSimpleFunction } from 'Common/Utils';
import { Capa, SaveSettingsStep } from 'Common/Enums';
import { Settings } from 'Common/Globals';
import { SettingsCapa } from 'Common/Globals';
import { i18n, trigger as translatorTrigger } from 'Common/Translator';
import { AbstractViewSettings } from 'Knoin/AbstractViews';
import { SettingsUserStore } from 'Stores/User/Settings';
import { GnuPGUserStore } from 'Stores/User/GnuPG';
import { OpenPGPUserStore } from 'Stores/User/OpenPGP';
import Remote from 'Remote/User/Fetch';
export class SecurityUserSettings {
import { showScreenPopup } from 'Knoin/Knoin';
import { OpenPgpImportPopupView } from 'View/Popup/OpenPgpImport';
import { OpenPgpGeneratePopupView } from 'View/Popup/OpenPgpGenerate';
export class UserSettingsSecurity extends AbstractViewSettings {
constructor() {
this.capaAutoLogout = Settings.capa(Capa.AutoLogout);
super();
this.capaAutoLogout = SettingsCapa('AutoLogout');
this.autoLogout = SettingsUserStore.autoLogout;
this.autoLogoutTrigger = ko.observable(SaveSettingsStep.Idle);
let i18nLogout = (key, params) => i18n('SETTINGS_SECURITY/AUTOLOGIN_' + key, params);
this.autoLogoutOptions = ko.computed(() => {
this.autoLogoutOptions = koComputable(() => {
translatorTrigger();
return [
{ id: 0, name: i18nLogout('NEVER_OPTION_NAME') },
@ -32,10 +41,37 @@ export class SecurityUserSettings {
});
if (this.capaAutoLogout) {
this.autoLogout.subscribe(value => Remote.saveSetting(
'AutoLogout', pInt(value),
settingsSaveHelperSimpleFunction(this.autoLogoutTrigger, this)
));
this.addSetting('AutoLogout');
}
this.gnupgPublicKeys = GnuPGUserStore.publicKeys;
this.gnupgPrivateKeys = GnuPGUserStore.privateKeys;
this.openpgpkeysPublic = OpenPGPUserStore.publicKeys;
this.openpgpkeysPrivate = OpenPGPUserStore.privateKeys;
this.canOpenPGP = SettingsCapa('OpenPGP');
this.canGnuPG = GnuPGUserStore.isSupported();
this.canMailvelope = !!window.mailvelope;
this.allowDraftAutosave = SettingsUserStore.allowDraftAutosave;
this.allowDraftAutosave.subscribe(value => Remote.saveSetting('AllowDraftAutosave', value))
}
addOpenPgpKey() {
showScreenPopup(OpenPgpImportPopupView);
}
generateOpenPgpKey() {
showScreenPopup(OpenPgpGeneratePopupView);
}
onBuild() {
/**
* Create an iframe to display the Mailvelope keyring settings.
* The iframe will be injected into the container identified by selector.
*/
window.mailvelope && mailvelope.createSettingsContainer('#mailvelope-settings'/*[, keyring], options*/);
}
}

View file

@ -10,7 +10,7 @@ import { showScreenPopup } from 'Knoin/Knoin';
import { TemplatePopupView } from 'View/Popup/Template';
import { addComputablesTo } from 'Common/Utils';
export class TemplatesUserSettings {
export class UserSettingsTemplates {
constructor() {
this.templates = TemplateUserStore.templates;

View file

@ -1,33 +1,37 @@
import ko from 'ko';
import { addObservablesTo } from 'External/ko';
import { SaveSettingsStep, UploadErrorCode, Capa } from 'Common/Enums';
import { SaveSettingsStep, UploadErrorCode } from 'Common/Enums';
import { changeTheme, convertThemeName } from 'Common/Utils';
import { themePreviewLink, serverRequest } from 'Common/Links';
import { i18n } from 'Common/Translator';
import { Settings } from 'Common/Globals';
import { SettingsCapa } from 'Common/Globals';
import { ThemeStore } from 'Stores/Theme';
import Remote from 'Remote/User/Fetch';
export class ThemesUserSettings {
const themeBackground = {
name: ThemeStore.userBackgroundName,
hash: ThemeStore.userBackgroundHash
};
addObservablesTo(themeBackground, {
uploaderButton: null,
loading: false,
error: ''
});
export class UserSettingsThemes /*extends AbstractViewSettings*/ {
constructor() {
this.theme = ThemeStore.theme;
this.themes = ThemeStore.themes;
this.themesObjects = ko.observableArray();
this.background = {};
this.background.name = ThemeStore.userBackgroundName;
this.background.hash = ThemeStore.userBackgroundHash;
this.background.uploaderButton = ko.observable(null);
this.background.loading = ko.observable(false);
this.background.error = ko.observable('');
this.capaUserBackground = ko.observable(Settings.capa(Capa.UserBackground));
themeBackground.enabled = SettingsCapa('UserBackground');
this.background = themeBackground;
this.themeTrigger = ko.observable(SaveSettingsStep.Idle).extend({ debounce: 100 });
this.theme.subscribe((value) => {
ThemeStore.theme.subscribe(value => {
this.themesObjects.forEach(theme => {
theme.selected(value === theme.name);
});
@ -41,10 +45,10 @@ export class ThemesUserSettings {
}
onBuild() {
const currentTheme = this.theme();
const currentTheme = ThemeStore.theme();
this.themesObjects(
this.themes.map(theme => ({
ThemeStore.themes.map(theme => ({
name: theme,
nameDisplay: convertThemeName(theme),
selected: ko.observable(theme === currentTheme),
@ -54,28 +58,28 @@ export class ThemesUserSettings {
// initUploader
if (this.background.uploaderButton() && this.capaUserBackground()) {
if (themeBackground.uploaderButton() && themeBackground.enabled) {
const oJua = new Jua({
action: serverRequest('UploadBackground'),
limit: 1,
clickElement: this.background.uploaderButton()
clickElement: themeBackground.uploaderButton()
});
oJua
.on('onStart', () => {
this.background.loading(true);
this.background.error('');
themeBackground.loading(true);
themeBackground.error('');
return true;
})
.on('onComplete', (id, result, data) => {
this.background.loading(false);
themeBackground.loading(false);
if (result && id && data && data.Result && data.Result.Name && data.Result.Hash) {
this.background.name(data.Result.Name);
this.background.hash(data.Result.Hash);
themeBackground.name(data.Result.Name);
themeBackground.hash(data.Result.Hash);
} else {
this.background.name('');
this.background.hash('');
themeBackground.name('');
themeBackground.hash('');
let errorMsg = '';
if (data.ErrorCode) {
@ -94,7 +98,7 @@ export class ThemesUserSettings {
errorMsg = data.ErrorMessage;
}
this.background.error(errorMsg || i18n('SETTINGS_THEMES/ERROR_UNKNOWN'));
themeBackground.error(errorMsg || i18n('SETTINGS_THEMES/ERROR_UNKNOWN'));
}
return true;
@ -103,14 +107,14 @@ export class ThemesUserSettings {
}
onShow() {
this.background.error('');
themeBackground.error('');
}
clearBackground() {
if (this.capaUserBackground()) {
Remote.clearUserBackground(() => {
this.background.name('');
this.background.hash('');
if (themeBackground.enabled) {
Remote.request('ClearUserBackground', () => {
themeBackground.name('');
themeBackground.hash('');
});
}
}