Merge branch 'master' into plugin-hooks

# Conflicts:
#	dev/View/User/Login.js
This commit is contained in:
djmaze 2021-04-15 16:58:59 +02:00
commit 2ab42b1f03
547 changed files with 29045 additions and 52993 deletions

View file

@ -64,8 +64,7 @@ class FolderSystemPopupView extends AbstractViewPopup {
DraftFolder: FolderUserStore.draftFolder(),
SpamFolder: FolderUserStore.spamFolder(),
TrashFolder: FolderUserStore.trashFolder(),
ArchiveFolder: FolderUserStore.archiveFolder(),
NullFolder: 'NullFolder'
ArchiveFolder: FolderUserStore.archiveFolder()
});
}).debounce(1000),
fCallback = () => {

View file

@ -1,193 +0,0 @@
import { Capa } from 'Common/Enums';
import { Settings } from 'Common/Globals';
import { pString } from 'Common/Utils';
import { i18n, trigger as translatorTrigger } from 'Common/Translator';
import Remote from 'Remote/User/Fetch';
import { showScreenPopup } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { TwoFactorTestPopupView } from 'View/Popup/TwoFactorTest';
class TwoFactorConfigurationPopupView extends AbstractViewPopup {
constructor() {
super('TwoFactorConfiguration');
this.addObservables({
lock: false,
processing: false,
clearing: false,
secreting: false,
viewUser: '',
twoFactorStatus: false,
twoFactorTested: false,
viewSecret: '',
viewBackupCodes: '',
viewUrlTitle: '',
viewUrl: '',
viewEnable_: false
});
this.capaTwoFactor = Settings.capa(Capa.TwoFactor);
const fn = iError => iError && this.viewEnable_(false);
this.addComputables({
viewEnable: {
read: this.viewEnable_,
write: (value) => {
value = !!value;
if (value && this.twoFactorTested()) {
this.viewEnable_(value);
Remote.enableTwoFactor(fn, value);
} else {
if (!value) {
this.viewEnable_(value);
}
Remote.enableTwoFactor(fn, false);
}
}
},
viewTwoFactorEnableTooltip: () => {
translatorTrigger();
return this.twoFactorTested() || this.viewEnable_()
? ''
: i18n('POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_TEST_BEFORE_DESC');
},
viewTwoFactorStatus: () => {
translatorTrigger();
return i18n(
this.twoFactorStatus()
? 'POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_CONFIGURED_DESC'
: 'POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC'
);
},
twoFactorAllowedEnable: () => this.viewEnable() || this.twoFactorTested()
});
this.onResult = this.onResult.bind(this);
this.onShowSecretResult = this.onShowSecretResult.bind(this);
}
showSecret() {
this.secreting(true);
Remote.showTwoFactorSecret(this.onShowSecretResult);
}
hideSecret() {
this.viewSecret('');
this.viewBackupCodes('');
this.viewUrlTitle('');
this.viewUrl('');
}
createTwoFactor() {
this.processing(true);
Remote.createTwoFactor(this.onResult);
}
logout() {
rl.app.logout();
}
testTwoFactor() {
showScreenPopup(TwoFactorTestPopupView, [this.twoFactorTested]);
}
clearTwoFactor() {
this.viewSecret('');
this.viewBackupCodes('');
this.viewUrlTitle('');
this.viewUrl('');
this.twoFactorTested(false);
this.clearing(true);
Remote.clearTwoFactor(this.onResult);
}
onShow(bLock) {
this.lock(!!bLock);
this.viewSecret('');
this.viewBackupCodes('');
this.viewUrlTitle('');
this.viewUrl('');
}
onHide() {
if (this.lock()) {
location.reload();
}
}
getQr() {
return (
'otpauth://totp/' +
encodeURIComponent(this.viewUser()) +
'?secret=' +
encodeURIComponent(this.viewSecret()) +
'&issuer=' +
encodeURIComponent('')
);
}
onResult(iError, oData) {
this.processing(false);
this.clearing(false);
if (iError) {
this.viewUser('');
this.viewEnable_(false);
this.twoFactorStatus(false);
this.twoFactorTested(false);
this.viewSecret('');
this.viewBackupCodes('');
this.viewUrlTitle('');
this.viewUrl('');
} else {
this.viewUser(pString(oData.Result.User));
this.viewEnable_(!!oData.Result.Enable);
this.twoFactorStatus(!!oData.Result.IsSet);
this.twoFactorTested(!!oData.Result.Tested);
this.viewSecret(pString(oData.Result.Secret));
this.viewBackupCodes(pString(oData.Result.BackupCodes).replace(/[\s]+/g, ' '));
this.viewUrlTitle(pString(oData.Result.UrlTitle));
this.viewUrl(qr.toDataURL({ level: 'M', size: 8, value: this.getQr() }));
}
}
onShowSecretResult(iError, data) {
this.secreting(false);
if (iError) {
this.viewSecret('');
this.viewUrlTitle('');
this.viewUrl('');
} else {
this.viewSecret(pString(data.Result.Secret));
this.viewUrlTitle(pString(data.Result.UrlTitle));
this.viewUrl(qr.toDataURL({ level: 'M', size: 6, value: this.getQr() }));
}
}
onBuild() {
if (this.capaTwoFactor) {
this.processing(true);
Remote.getTwoFactor(this.onResult);
}
}
}
export { TwoFactorConfigurationPopupView, TwoFactorConfigurationPopupView as default };

View file

@ -1,51 +0,0 @@
import Remote from 'Remote/User/Fetch';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
class TwoFactorTestPopupView extends AbstractViewPopup {
constructor() {
super('TwoFactorTest');
this.addObservables({
code: '',
codeStatus: null,
testing: false
});
this.koTestedTrigger = null;
decorateKoCommands(this, {
testCodeCommand: self => self.code() && !self.testing()
});
}
testCodeCommand() {
this.testing(true);
Remote.testTwoFactor(iError => {
this.testing(false);
this.codeStatus(!iError);
if (this.koTestedTrigger && this.codeStatus()) {
this.koTestedTrigger(true);
}
}, this.code());
}
clearPopup() {
this.code('');
this.codeStatus(null);
this.testing(false);
this.koTestedTrigger = null;
}
onShow(koTestedTrigger) {
this.clearPopup();
this.koTestedTrigger = koTestedTrigger;
}
}
export { TwoFactorTestPopupView, TwoFactorTestPopupView as default };

View file

@ -43,7 +43,6 @@ class LoginUserView extends AbstractViewCenter {
email: SettingsGet('DevEmail'),
password: SettingsGet('DevPassword'),
signMe: false,
additionalCode: '',
emailError: false,
passwordError: false,
@ -56,9 +55,6 @@ class LoginUserView extends AbstractViewCenter {
langRequest: false,
additionalCodeError: false,
additionalCodeSignMe: false,
additionalCodeVisibility: false,
signMeType: LoginSignMeType.Unused
});
@ -84,15 +80,10 @@ class LoginUserView extends AbstractViewCenter {
this.addSubscribables({
email: () => {
this.emailError(false);
this.additionalCode('');
this.additionalCodeVisibility(false);
},
password: () => this.passwordError(false),
additionalCode: () => this.additionalCodeError(false),
additionalCodeVisibility: () => this.additionalCodeError(false),
submitError: value => value || this.submitErrorAddidional(''),
signMeType: iValue => this.signMe(LoginSignMeType.DefaultOn === iValue),
@ -121,16 +112,13 @@ class LoginUserView extends AbstractViewCenter {
submitCommand(self, event) {
let email = this.email().trim(),
valid = event.target.form.reportValidity() && email,
pass = this.password(),
totp = this.additionalCodeVisibility(),
code = totp ? this.additionalCode() : '';
pass = this.password();
this.emailError(!email);
this.passwordError(!pass);
this.additionalCodeError(totp && !code);
let pluginResultCode = 0, pluginResultMessage = '';
Plugins.runHook('user-login-submit', [(iResultCode, sResultMessage) => {
runHook('user-login-submit', [(iResultCode, sResultMessage) => {
pluginResultCode = iResultCode;
pluginResultMessage = sResultMessage;
}]);
@ -156,13 +144,6 @@ class LoginUserView extends AbstractViewCenter {
}
this.submitError(getNotification(iError, oData.ErrorMessage, Notification.UnknownNotification));
this.submitErrorAddidional((oData && oData.ErrorMessageAdditional) || '');
} else if (oData.TwoFactorAuth) {
this.submitRequest(false);
this.additionalCode('');
this.additionalCodeVisibility(true);
let input = this.querySelector('.inputAdditionalCode');
input.required = true;
setTimeout(() => input.focus(), 100);
} else {
rl.route.reload();
}
@ -170,9 +151,7 @@ class LoginUserView extends AbstractViewCenter {
email,
pass,
!!this.signMe(),
this.bSendLanguage ? this.language() : '',
code,
!!(totp && this.additionalCodeSignMe())
this.bSendLanguage ? this.language() : ''
);
Local.set(ClientSideKeyName.LastSignMe, this.signMe() ? '-1-' : '-0-');

View file

@ -26,7 +26,6 @@ export class FolderListMailBoxUserView extends AbstractViewLeft {
this.composeInEdit = AppUserStore.composeInEdit;
this.messageList = MessageUserStore.list;
this.folderList = FolderUserStore.folderList;
this.folderListSystem = FolderUserStore.folderListSystem;
this.foldersChanging = FolderUserStore.foldersChanging;

View file

@ -52,7 +52,6 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
constructor() {
super('User/MailBox/MessageList', 'MailMessageList');
this.sLastUid = null;
this.bPrefetch = false;
this.emptySubjectValue = '';
@ -69,43 +68,34 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
this.popupVisibility = ko.computed(() => 0 < popupVisibilityNames().length);
this.message = MessageUserStore.message;
this.messageList = MessageUserStore.list;
this.messageListDisableAutoSelect = MessageUserStore.listDisableAutoSelect;
this.folderList = FolderUserStore.folderList;
this.sortSupported = FolderUserStore.sortSupported;
this.composeInEdit = AppUserStore.composeInEdit;
this.leftPanelDisabled = leftPanelDisabled;
this.selectorMessageSelected = MessageUserStore.selectorMessageSelected;
this.selectorMessageFocused = MessageUserStore.selectorMessageFocused;
this.isMessageSelected = MessageUserStore.isMessageSelected;
this.messageListSearch = MessageUserStore.listSearch;
this.messageListThreadUid = MessageUserStore.listThreadUid;
this.messageListError = MessageUserStore.listError;
this.folderMenuForMove = FolderUserStore.folderMenuForMove;
this.useCheckboxesInList = SettingsUserStore.useCheckboxesInList;
this.mainMessageListSearch = MessageUserStore.mainMessageListSearch;
this.messageListEndFolder = MessageUserStore.listEndFolder;
this.messageListEndThreadUid = MessageUserStore.listEndThreadUid;
this.messageListCheckedOrSelected = MessageUserStore.listCheckedOrSelected;
this.messageListCheckedOrSelectedUidsWithSubMails = MessageUserStore.listCheckedOrSelectedUidsWithSubMails;
this.messageListCompleteLoadingThrottle = MessageUserStore.listCompleteLoading;
this.messageListCompleteLoadingThrottleForAnimation = MessageUserStore.listLoadingAnimation;
initOnStartOrLangChange(() => this.emptySubjectValue = i18n('MESSAGE_LIST/EMPTY_SUBJECT_TEXT'));
this.userQuota = QuotaUserStore.quota;
this.userUsageSize = QuotaUserStore.usage;
this.userUsageProc = QuotaUserStore.percentage;
this.addObservables({
moveDropdownTrigger: false,
moreDropdownTrigger: false,
sortDropdownTrigger: false,
dragOverArea: null,
dragOverBodyArea: null,
@ -137,7 +127,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
},
inputProxyMessageListSearch: {
read: this.mainMessageListSearch,
read: MessageUserStore.mainMessageListSearch,
write: value => this.sLastSearchValue = value
},
@ -146,19 +136,19 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
return c && MessageUserStore.list.length > c;
},
hasMessages: () => 0 < this.messageList.length,
hasMessages: () => 0 < MessageUserStore.list.length,
isSpamFolder: () => (FolderUserStore.spamFolder() || 0) === this.messageListEndFolder(),
isSpamFolder: () => (FolderUserStore.spamFolder() || 0) === MessageUserStore.listEndFolder(),
isSpamDisabled: () => UNUSED_OPTION_VALUE === FolderUserStore.spamFolder(),
isTrashFolder: () => (FolderUserStore.trashFolder() || 0) === this.messageListEndFolder(),
isTrashFolder: () => (FolderUserStore.trashFolder() || 0) === MessageUserStore.listEndFolder(),
isDraftFolder: () => (FolderUserStore.draftFolder() || 0) === this.messageListEndFolder(),
isDraftFolder: () => (FolderUserStore.draftFolder() || 0) === MessageUserStore.listEndFolder(),
isSentFolder: () => (FolderUserStore.sentFolder() || 0) === this.messageListEndFolder(),
isSentFolder: () => (FolderUserStore.sentFolder() || 0) === MessageUserStore.listEndFolder(),
isArchiveFolder: () => (FolderUserStore.archiveFolder() || 0) === this.messageListEndFolder(),
isArchiveFolder: () => (FolderUserStore.archiveFolder() || 0) === MessageUserStore.listEndFolder(),
isArchiveDisabled: () => UNUSED_OPTION_VALUE === FolderUserStore.archiveFolder(),
@ -174,17 +164,28 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
mobileCheckedStateHide: () => ThemeStore.isMobile() ? !MessageUserStore.listChecked().length : true,
messageListFocused: () => Scope.MessageList === AppUserStore.focusedState()
messageListFocused: () => Scope.MessageList === AppUserStore.focusedState(),
sortText: () => {
let mode = FolderUserStore.sortMode(),
desc = '' === mode || mode.includes('REVERSE');
mode = mode.split(/\s+/);
if (mode.includes('FROM')) {
return '@' + (desc ? '⬆' : '⬇');
}
if (mode.includes('SUBJECT')) {
return '𝐒' + (desc ? '⬆' : '⬇');
}
return (mode.includes('SIZE') ? '✉' : '📅') + (desc ? '⬇' : '⬆');
}
});
this.hasCheckedOrSelectedLines = MessageUserStore.hasCheckedOrSelected,
this.quotaTooltip = this.quotaTooltip.bind(this);
this.selector = new Selector(
this.messageList,
this.selectorMessageSelected,
this.selectorMessageFocused,
MessageUserStore.list,
MessageUserStore.selectorMessageSelected,
MessageUserStore.selectorMessageFocused,
'.messageListItem .actionHandle',
'.messageListItem .checkboxMessage',
'.messageListItem.focused'
@ -209,7 +210,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
addEventListener('mailbox.message.show', e => {
const sFolder = e.detail.Folder, sUid = e.detail.Uid;
const message = this.messageList.find(
const message = MessageUserStore.list.find(
item => item && sFolder === item.folder && sUid === item.uid
);
@ -246,6 +247,11 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
});
}
changeSort(self, event) {
FolderUserStore.sortMode(event.target.closest('li').dataset.sort);
this.reloadCommand();
}
clearCommand() {
if (Settings.capa(Capa.DangerousActions)) {
showScreenPopup(FolderClearPopupView, [FolderUserStore.currentFolder()]);
@ -375,7 +381,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
return false;
});
if (!SettingsUserStore.usePreviewPane() && !this.message()) {
if (!SettingsUserStore.usePreviewPane() && !MessageUserStore.message()) {
this.selector.iFocusedNextHelper = up ? -1 : 1;
} else {
this.selector.iSelectNextHelper = up ? -1 : 1;
@ -391,18 +397,18 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
}
useAutoSelect() {
return !this.messageListDisableAutoSelect()
&& !/is:unseen/.test(this.mainMessageListSearch())
return !MessageUserStore.listDisableAutoSelect()
&& !/is:unseen/.test(MessageUserStore.mainMessageListSearch())
&& SettingsUserStore.usePreviewPane();
}
searchEnterAction() {
this.mainMessageListSearch(this.sLastSearchValue);
MessageUserStore.mainMessageListSearch(this.sLastSearchValue);
this.inputMessageListSearchFocus(false);
}
cancelSearch() {
this.mainMessageListSearch('');
MessageUserStore.mainMessageListSearch('');
this.inputMessageListSearchFocus(false);
}
@ -571,7 +577,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
}
flagMessages(currentMessage) {
const checked = this.messageListCheckedOrSelected();
const checked = MessageUserStore.listCheckedOrSelected();
if (currentMessage) {
const checkedUids = checked.map(message => message.uid);
if (checkedUids.includes(currentMessage.uid)) {
@ -591,7 +597,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
}
flagMessagesFast(bFlag) {
const checked = this.messageListCheckedOrSelected();
const checked = MessageUserStore.listCheckedOrSelected();
if (checked.length) {
if (undefined === bFlag) {
const flagged = checked.filter(message => message.isFlagged());
@ -611,7 +617,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
}
seenMessagesFast(seen) {
const checked = this.messageListCheckedOrSelected();
const checked = MessageUserStore.listCheckedOrSelected();
if (checked.length) {
if (undefined === seen) {
const unseen = checked.filter(message => message.isUnseen());
@ -656,7 +662,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
!this.messageListSearchDesc() &&
!this.messageListError() &&
!this.messageListEndThreadUid() &&
this.messageList.length &&
MessageUserStore.list.length &&
(this.isSpamFolder() || this.isTrashFolder())
);
}
@ -700,7 +706,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
initShortcuts() {
shortcuts.add('enter,open', '', Scope.MessageList, () => {
if (this.message() && this.useAutoSelect()) {
if (MessageUserStore.message() && this.useAutoSelect()) {
dispatchEvent(new CustomEvent('mailbox.message-view.toggle-full-screen'));
return false;
}
@ -756,9 +762,9 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
}
shortcuts.add('t', '', [Scope.MessageList], () => {
let message = this.selectorMessageSelected();
let message = MessageUserStore.selectorMessageSelected();
if (!message) {
message = this.selectorMessageFocused();
message = MessageUserStore.selectorMessageFocused();
}
if (message && 0 < message.threadsLen()) {
@ -831,7 +837,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
return false;
});
shortcuts.add('tab,arrowright', '', Scope.MessageList, () => {
this.message() && AppUserStore.focusedState(Scope.MessageView);
MessageUserStore.message() && AppUserStore.focusedState(Scope.MessageView);
return false;
});
@ -841,7 +847,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
prefetchNextTick() {
if (!this.bPrefetch && !ifvisible.now() && this.viewModelVisible) {
const message = this.messageList.find(
const message = MessageUserStore.list.find(
item => item && !hasRequestedMessage(item.folder, item.uid)
);
if (message) {
@ -866,15 +872,15 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
advancedSearchClick() {
Settings.capa(Capa.SearchAdv)
&& showScreenPopup(AdvancedSearchPopupView, [this.mainMessageListSearch()]);
&& showScreenPopup(AdvancedSearchPopupView, [MessageUserStore.mainMessageListSearch()]);
}
quotaTooltip() {
return i18n('MESSAGE_LIST/QUOTA_SIZE', {
SIZE: FileInfo.friendlySize(this.userUsageSize()),
PROC: this.userUsageProc(),
LIMIT: FileInfo.friendlySize(this.userQuota())
});
SIZE: FileInfo.friendlySize(QuotaUserStore.usage()),
PROC: QuotaUserStore.percentage(),
LIMIT: FileInfo.friendlySize(QuotaUserStore.quota())
}).replace(/<[^>]+>/g, '');
}
initUploaderForAppend() {

View file

@ -71,8 +71,6 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
moreDropdownTrigger: false
});
this.pswp = null;
this.moveAction = moveAction;
this.allowComposer = Settings.capa(Capa.Composer);
@ -84,7 +82,6 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
this.message = MessageUserStore.message;
this.hasCheckedMessages = MessageUserStore.hasCheckedMessages;
this.messageListCheckedOrSelectedUidsWithSubMails = MessageUserStore.listCheckedOrSelectedUidsWithSubMails;
this.messageLoadingThrottle = MessageUserStore.messageLoading;
this.messagesBodiesDom = MessageUserStore.messagesBodiesDom;
this.useThreads = SettingsUserStore.useThreads;
@ -136,6 +133,8 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
viewReplyTo: '',
viewTimeStamp: 0,
viewSize: '',
viewSpamScore: 0,
viewSpamStatus: '',
viewLineAsCss: '',
viewViewLink: '',
viewUnsubscribeLink: '',
@ -220,13 +219,15 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
this.viewFromShort(message.fromToLine(true, true));
this.viewFromDkimData(message.fromDkimData());
this.viewToShort(message.toToLine(true, true));
this.viewFrom(message.fromToLine(false));
this.viewTo(message.toToLine(false));
this.viewCc(message.ccToLine(false));
this.viewBcc(message.bccToLine(false));
this.viewReplyTo(message.replyToToLine(false));
this.viewFrom(message.fromToLine());
this.viewTo(message.toToLine());
this.viewCc(message.ccToLine());
this.viewBcc(message.bccToLine());
this.viewReplyTo(message.replyToToLine());
this.viewTimeStamp(message.dateTimeStampInUTC());
this.viewSize(message.friendlySize());
this.viewSpamScore(message.spamScore());
this.viewSpamStatus(i18n(message.isSpam() ? 'GLOBAL/SPAM' : 'GLOBAL/NOT_SPAM') + ': ' + message.spamResult());
this.viewLineAsCss(message.lineAsCss());
this.viewViewLink(message.viewLink());
this.viewUnsubscribeLink(message.getFirstUnsubsribeLink());
@ -717,7 +718,7 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
* @returns {string}
*/
printableCheckedMessageCount() {
const cnt = this.messageListCheckedOrSelectedUidsWithSubMails().length;
const cnt = MessageUserStore.listCheckedOrSelectedUidsWithSubMails().length;
return 0 < cnt ? (100 > cnt ? cnt : '99+') : '';
}