Move the "upload EML file to mailbox" Append feature into a DoFolderAppend()

This commit is contained in:
the-djmaze 2023-02-16 13:13:23 +01:00
parent fb2eb62f83
commit 5216535278
8 changed files with 102 additions and 145 deletions

View file

@ -9,8 +9,6 @@ import { SettingsUserStore } from 'Stores/User/Settings';
import { FolderUserStore } from 'Stores/User/Folder'; import { FolderUserStore } from 'Stores/User/Folder';
import { MessagelistUserStore } from 'Stores/User/Messagelist'; import { MessagelistUserStore } from 'Stores/User/Messagelist';
import { getNotification } from 'Common/Translator'; import { getNotification } from 'Common/Translator';
import { Settings } from 'Common/Globals';
import { serverRequest } from 'Common/Links';
import Remote from 'Remote/User/Fetch'; import Remote from 'Remote/User/Fetch';
@ -286,28 +284,20 @@ moveMessagesToFolder = (sFromFolderFullName, oUids, sToFolderFullName, bCopy) =>
}, },
dropFilesInFolder = (sFolderFullName, files) => { dropFilesInFolder = (sFolderFullName, files) => {
let count = 0, let count = files.length;
fn = () => 0 == --count
&& FolderUserStore.currentFolderFullName() == sFolderFullName
&& MessagelistUserStore.reload(true, true);
for (const file of files) { for (const file of files) {
if ('message/rfc822' === file.type) { if ('message/rfc822' === file.type) {
++count;
let data = new FormData; let data = new FormData;
data.append('folder', sFolderFullName); data.append('folder', sFolderFullName);
data.append('appendFile', file); data.append('appendFile', file);
data.XToken = Settings.app('token'); Remote.request('FolderAppend', (iError, data)=>{
fetch(serverRequest('Append'), { iError && console.error(data.ErrorMessage);
method: 'POST', 0 == --count
mode: 'same-origin', && FolderUserStore.currentFolderFullName() == sFolderFullName
cache: 'no-cache', && MessagelistUserStore.reload(true, true);
redirect: 'error', }, data);
referrerPolicy: 'no-referrer', } else {
credentials: 'same-origin', --count;
body: data
})
.then(fn)
.catch(fn);
} }
} }
}; };

20
dev/bootstrap.js vendored
View file

@ -44,21 +44,31 @@ export default App => {
}, init); }, init);
if (postData) { if (postData) {
init.method = 'POST'; init.method = 'POST';
init.headers['Content-Type'] = 'application/json'; let asJSON = 1,
XToken = Settings.app('token'),
object = {};
if (postData instanceof FormData) { if (postData instanceof FormData) {
const object = {};
postData.forEach((value, key) => { postData.forEach((value, key) => {
if (!Reflect.has(object, key)){ if (value instanceof File) {
asJSON = 0;
} else if (!Reflect.has(object, key)) {
object[key] = value; object[key] = value;
} else { } else {
isArray(object[key]) || (object[key] = [object[key]]); isArray(object[key]) || (object[key] = [object[key]]);
object[key].push(value); object[key].push(value);
} }
}); });
if (asJSON) {
postData = object; postData = object;
} else {
postData.set('XToken', XToken);
} }
postData.XToken = Settings.app('token'); }
init.body = JSON.stringify(postData); if (asJSON) {
init.headers['Content-Type'] = 'application/json';
postData = JSON.stringify(postData);
}
init.body = postData;
} }
init.headers['X-SM-Token'] = Settings.app('token'); init.headers['X-SM-Token'] = Settings.app('token');
// init.headers = new Headers(init.headers); // init.headers = new Headers(init.headers);

View file

@ -2,8 +2,6 @@
namespace RainLoop; namespace RainLoop;
use RainLoop\Enumerations\UploadError;
class Actions class Actions
{ {
use Actions\Admin; use Actions\Admin;
@ -942,52 +940,6 @@ class Actions
return \MailSo\Base\Utils::SecureFileName(\MailSo\Base\Utils::Utf8Clear($sClearedFileName)); return \MailSo\Base\Utils::SecureFileName(\MailSo\Base\Utils::Utf8Clear($sClearedFileName));
} }
protected function getUploadErrorMessageByCode(int $iError, int &$iClientError): string
{
$sError = '';
$iClientError = UploadError::NORMAL;
switch ($iError) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
case UploadError::CONFIG_SIZE:
case UploadError::EMPTY_FILES_DATA:
$sError = 'File is too big';
$iClientError = UploadError::FILE_IS_TOO_BIG;
break;
case UPLOAD_ERR_PARTIAL:
$sError = 'File partially uploaded';
$iClientError = UploadError::FILE_PARTIALLY_UPLOADED;
break;
case UPLOAD_ERR_NO_FILE:
$sError = 'No file uploaded';
$iClientError = UploadError::FILE_NO_UPLOADED;
break;
case UPLOAD_ERR_NO_TMP_DIR:
case UPLOAD_ERR_CANT_WRITE:
case UPLOAD_ERR_EXTENSION:
$sError = 'Missing temp folder';
$iClientError = UploadError::MISSING_TEMP_FOLDER;
break;
case UploadError::ON_SAVING:
$sError = 'Error on saving file';
$iClientError = UploadError::FILE_ON_SAVING_ERROR;
break;
case UploadError::FILE_TYPE:
$sError = 'Invalid file type';
$iClientError = UploadError::FILE_TYPE;
break;
case UploadError::UNKNOWN:
default:
$sError = 'Unknown error';
$iClientError = UploadError::UNKNOWN;
break;
}
return $sError;
}
public function Upload(?array $aFile, int $iError): array public function Upload(?array $aFile, int $iError): array
{ {
$oAccount = $this->getAccountFromToken(); $oAccount = $this->getAccountFromToken();
@ -1018,8 +970,8 @@ class Actions
} }
if (UPLOAD_ERR_OK !== $iError) { if (UPLOAD_ERR_OK !== $iError) {
$iClientError = Enumerations\UploadError::NORMAL; $iClientError = 0;
$sError = $this->getUploadErrorMessageByCode($iError, $iClientError); $sError = Enumerations\UploadError::getUserMessage($iError, $iClientError);
if (!empty($sError)) { if (!empty($sError)) {
$aResponse['ErrorCode'] = $iClientError; $aResponse['ErrorCode'] = $iClientError;

View file

@ -157,8 +157,8 @@ trait Contacts
} }
if (UPLOAD_ERR_OK !== $iError) { if (UPLOAD_ERR_OK !== $iError) {
$iClientError = \RainLoop\Enumerations\UploadError::NORMAL; $iClientError = 0;
$sError = $this->getUploadErrorMessageByCode($iError, $iClientError); $sError = \RainLoop\Enumerations\UploadError::getUserMessage($iError, $iClientError);
if (!empty($sError)) { if (!empty($sError)) {
return $this->FalseResponse($iClientError, $sError); return $this->FalseResponse($iClientError, $sError);
} }

View file

@ -14,32 +14,36 @@ trait Folders
* Appends uploaded rfc822 message to mailbox * Appends uploaded rfc822 message to mailbox
* @throws \MailSo\RuntimeException * @throws \MailSo\RuntimeException
*/ */
public function Append(): bool public function DoFolderAppend(): array
{ {
$oAccount = $this->initMailClientConnection(); $oAccount = $this->initMailClientConnection();
$sFolderFullName = $this->GetActionParam('folder', ''); $sFolderFullName = $this->GetActionParam('folder', '');
if ($oAccount if (!$this->oConfig->Get('labs', 'allow_message_append', false)) {
&& !empty($sFolderFullName) return $this->FalseResponse(999, 'Permission denied');
&& !empty($_FILES['appendFile']) }
&& \is_uploaded_file($_FILES['appendFile']['tmp_name'])
&& \UPLOAD_ERR_OK == $_FILES['appendFile']['error'] if (empty($_FILES['appendFile'])) {
&& $this->oConfig->Get('labs', 'allow_message_append', false) return $this->FalseResponse(999, 'No file');
) { }
if (\UPLOAD_ERR_OK != $_FILES['appendFile']['error']) {
return $this->FalseResponse($iErrorCode, \RainLoop\Enumerations\UploadError::getMessage($iErrorCode));
}
if ($oAccount && !empty($sFolderFullName) && \is_uploaded_file($_FILES['appendFile']['tmp_name'])) {
$sSavedName = 'append-post-' . \md5($sFolderFullName . $_FILES['appendFile']['name'] . $_FILES['appendFile']['tmp_name']); $sSavedName = 'append-post-' . \md5($sFolderFullName . $_FILES['appendFile']['name'] . $_FILES['appendFile']['tmp_name']);
if ($this->FilesProvider()->MoveUploadedFile($oAccount, $sSavedName, $_FILES['appendFile']['tmp_name'])) { if ($this->FilesProvider()->MoveUploadedFile($oAccount, $sSavedName, $_FILES['appendFile']['tmp_name'])) {
$iMessageStreamSize = $this->FilesProvider()->FileSize($oAccount, $sSavedName); $iMessageStreamSize = $this->FilesProvider()->FileSize($oAccount, $sSavedName);
$rMessageStream = $this->FilesProvider()->GetFile($oAccount, $sSavedName); $rMessageStream = $this->FilesProvider()->GetFile($oAccount, $sSavedName);
$this->MailClient()->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderFullName); $this->MailClient()->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderFullName);
$this->FilesProvider()->Clear($oAccount, $sSavedName); $this->FilesProvider()->Clear($oAccount, $sSavedName);
}
}
return $this->TrueResponse(); return $this->TrueResponse();
} }
}
return $this->FalseResponse(999);
}
public function DoFolders() : array public function DoFolders() : array
{ {

View file

@ -209,8 +209,8 @@ trait Themes
} }
if (UPLOAD_ERR_OK !== $iError) { if (UPLOAD_ERR_OK !== $iError) {
$iClientError = \RainLoop\Enumerations\UploadError::NORMAL; $iClientError = 0;
$sError = $this->getUploadErrorMessageByCode($iError, $iClientError); $sError = \RainLoop\Enumerations\UploadError::getUserMessage($iError, $iClientError);
if (!empty($sError)) { if (!empty($sError)) {
return $this->FalseResponse($iClientError, $sError); return $this->FalseResponse($iClientError, $sError);
} }

View file

@ -4,27 +4,62 @@ namespace RainLoop\Enumerations;
abstract class UploadError abstract class UploadError
{ {
// UPLOAD_ERR_OK; There is no error, the file uploaded with success.
const NORMAL = 0;
// UPLOAD_ERR_INI_SIZE; The uploaded file exceeds the upload_max_filesize directive in php.ini.
const FILE_IS_TOO_BIG = 1;
// UPLOAD_ERR_FORM_SIZE; The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.
// const FORM_SIZE = 2;
// UPLOAD_ERR_PARTIAL; The uploaded file was only partially uploaded.
const FILE_PARTIALLY_UPLOADED = 3;
// UPLOAD_ERR_NO_FILE; No file was uploaded.
const FILE_NO_UPLOADED = 4;
// UPLOAD_ERR_NO_TMP_DIR; Missing a temporary folder.
const MISSING_TEMP_FOLDER = 6;
// UPLOAD_ERR_CANT_WRITE; Failed to write file to disk.
const FILE_ON_SAVING_ERROR = 7;
// UPLOAD_ERR_EXTENSION; A PHP extension stopped the file upload
// const EXTENSION = 8;
const FILE_TYPE = 98; const FILE_TYPE = 98;
const UNKNOWN = 99; const UNKNOWN = 99;
const CONFIG_SIZE = 1001; const CONFIG_SIZE = 1001;
const ON_SAVING = 1002; const ON_SAVING = 1002;
const EMPTY_FILES_DATA = 1003; const EMPTY_FILES_DATA = 1003;
private static $messages = [
\UPLOAD_ERR_INI_SIZE => 'Filesize exceeds the upload_max_filesize directive in php.ini',
\UPLOAD_ERR_FORM_SIZE => 'Filesize exceeds the MAX_FILE_SIZE directive that was specified in the html form',
\UPLOAD_ERR_PARTIAL => 'File was only partially uploaded',
\UPLOAD_ERR_NO_FILE => 'No file was uploaded',
\UPLOAD_ERR_NO_TMP_DIR => 'Missing a temporary folder',
\UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk',
\UPLOAD_ERR_EXTENSION => 'File upload stopped by extension',
98 => 'Invalid file type',
99 => 'Unknown error',
1001 => 'Filesize exceeds the config setting',
1002 => 'Error saving file',
1003 => 'File is empty'
];
public static function getMessage(int $code): string
{
return isset(static::$messages[$code]) ? static::$messages[$code] : 0;
}
protected function getUserMessage(int $iError, int &$iClientError): string
{
$iClientError = $iError;
switch ($iError) {
case \UPLOAD_ERR_OK:
case \UPLOAD_ERR_PARTIAL:
case \UPLOAD_ERR_NO_FILE:
case static::FILE_TYPE:
break;
case \UPLOAD_ERR_INI_SIZE:
case \UPLOAD_ERR_FORM_SIZE:
case static::CONFIG_SIZE:
case static::EMPTY_FILES_DATA:
return 'File is too big';
case \UPLOAD_ERR_NO_TMP_DIR:
case \UPLOAD_ERR_CANT_WRITE:
case \UPLOAD_ERR_EXTENSION:
case static::ON_SAVING:
$iClientError = static::FILE_ON_SAVING_ERROR;
break;
default:
$iClientError = static::UNKNOWN;
break;
}
return static::getMessage($iClientError);
}
} }

View file

@ -77,7 +77,9 @@ class ServiceActions
$aResponse = null; $aResponse = null;
$oException = null; $oException = null;
if (empty($_POST) || (!empty($_SERVER['CONTENT_TYPE']) && \str_contains($_SERVER['CONTENT_TYPE'], 'application/json'))) {
$_POST = \json_decode(\file_get_contents('php://input'), true); $_POST = \json_decode(\file_get_contents('php://input'), true);
}
$sAction = $_POST['Action'] ?? ''; $sAction = $_POST['Action'] ?? '';
if (empty($sAction) && $this->oHttp->IsGet() && !empty($this->aPaths[2])) { if (empty($sAction) && $this->oHttp->IsGet() && !empty($this->aPaths[2])) {
@ -195,40 +197,6 @@ class ServiceActions
return $sResult; return $sResult;
} }
public function ServiceAppend() : string
{
\ob_start();
$bResponse = false;
$oException = null;
try
{
if (\method_exists($this->oActions, 'Append') && \is_callable(array($this->oActions, 'Append'))) {
isset($_POST) && $this->oActions->SetActionParams($_POST, 'Append');
$bResponse = $this->oActions->Append();
}
}
catch (\Throwable $oException)
{
$bResponse = false;
}
\header('Content-Type: text/plain; charset=utf-8');
$sResult = true === $bResponse ? '1' : '0';
$sObResult = \ob_get_clean();
if (\strlen($sObResult)) {
$this->Logger()->Write($sObResult, \LOG_ERR, 'OB-DATA');
}
if ($oException) {
$this->Logger()->WriteException($oException, \LOG_ERR);
}
$this->Logger()->Write($sResult, \LOG_INFO, 'APPEND');
return $sResult;
}
private function privateUpload(string $sAction, int $iSizeLimit = 0) : string private function privateUpload(string $sAction, int $iSizeLimit = 0) : string
{ {
$oConfig = $this->Config(); $oConfig = $this->Config();
@ -239,10 +207,8 @@ class ServiceActions
{ {
$aFile = null; $aFile = null;
$sInputName = 'uploader'; $sInputName = 'uploader';
$iError = Enumerations\UploadError::UNKNOWN;
$iSizeLimit = (0 < $iSizeLimit ? $iSizeLimit : ((int) $oConfig->Get('webmail', 'attachment_size_limit', 0))) * 1024 * 1024; $iSizeLimit = (0 < $iSizeLimit ? $iSizeLimit : ((int) $oConfig->Get('webmail', 'attachment_size_limit', 0))) * 1024 * 1024;
$iError = UPLOAD_ERR_OK;
$_FILES = isset($_FILES) ? $_FILES : null; $_FILES = isset($_FILES) ? $_FILES : null;
if (isset($_FILES[$sInputName], $_FILES[$sInputName]['name'], $_FILES[$sInputName]['tmp_name'], $_FILES[$sInputName]['size'])) { if (isset($_FILES[$sInputName], $_FILES[$sInputName]['name'], $_FILES[$sInputName]['tmp_name'], $_FILES[$sInputName]['size'])) {
$iError = (isset($_FILES[$sInputName]['error'])) ? (int) $_FILES[$sInputName]['error'] : UPLOAD_ERR_OK; $iError = (isset($_FILES[$sInputName]['error'])) ? (int) $_FILES[$sInputName]['error'] : UPLOAD_ERR_OK;