diff --git a/.vscode/ftp-kr.sync.cache.json b/.vscode/ftp-kr.sync.cache.json index 52ab8b9..a01f4c1 100644 --- a/.vscode/ftp-kr.sync.cache.json +++ b/.vscode/ftp-kr.sync.cache.json @@ -24,14 +24,14 @@ }, "MailToTaskImporter.php": { "type": "-", - "size": 24511, - "lmtime": 1770587036920, + "size": 37407, + "lmtime": 1770734028354, "modified": false }, "TaskAttachmentRepository.php": { "type": "-", - "size": 8411, - "lmtime": 0, + "size": 8806, + "lmtime": 1770731454505, "modified": false }, "WorkTimeRepository.php": { @@ -138,8 +138,8 @@ ".claude": { "settings.local.json": { "type": "-", - "size": 72, - "lmtime": 1770583517578, + "size": 265, + "lmtime": 1770734134148, "modified": false } }, @@ -175,6 +175,12 @@ }, "layout": {}, "libraries": {}, + "logs.txt": { + "type": "-", + "size": 1016, + "lmtime": 1770733260000, + "modified": false + }, "REFACTORING_PLAN.md": { "type": "-", "size": 3576, @@ -210,8 +216,8 @@ }, "task_edit.php": { "type": "-", - "size": 10202, - "lmtime": 0, + "size": 10285, + "lmtime": 1770733553999, "modified": false }, "task_popup.php": { @@ -272,6 +278,22 @@ "lmtime": 0, "modified": false } + }, + "html": { + "textarea.php": { + "type": "-", + "size": 1383, + "lmtime": 1770733546656, + "modified": false + } + }, + "projects": { + "task-edit.php": { + "type": "-", + "size": 7739, + "lmtime": 1770733570166, + "modified": false + } } }, "tests": { diff --git a/autoload/Domain/Tasks/MailToTaskImporter.php b/autoload/Domain/Tasks/MailToTaskImporter.php index da6be39..4400e75 100644 --- a/autoload/Domain/Tasks/MailToTaskImporter.php +++ b/autoload/Domain/Tasks/MailToTaskImporter.php @@ -172,24 +172,30 @@ class MailToTaskImporter continue; } - // Konwertuj inline images do Base64 i osadź w treści - $cid_to_data_uri = []; + // Zapisz inline images jako załączniki i zbierz URLe + $cid_to_url = []; if ( isset( $content['inline_images'] ) && is_array( $content['inline_images'] ) ) { foreach ( $content['inline_images'] as $cid => $inline_image ) { - // Konwertuj obraz do Base64 data URI - $data_uri = $this -> convertToDataUri( $inline_image['content'], $inline_image['mime'] ); - if ( $data_uri !== '' ) - $cid_to_data_uri[$cid] = $data_uri; + $img_name = trim( $inline_image['name'] ); + if ( $img_name === '' ) + $img_name = 'inline_' . md5( $cid ) . '.' . $this -> guessExtensionFromMime( $inline_image['mime'] ); + + $result = $this -> attachments -> uploadFromContent( $task_id, self::TASK_USER_ID, $img_name, $inline_image['content'] ); + if ( is_array( $result ) && $result['status'] === 'success' ) + $cid_to_url[$cid] = '/upload/task_attachments/' . $result['relative_path'] . '/' . $result['stored_name']; } } - // Jeśli są inline images i HTML, zastąp CIDy na Base64 data URI i użyj HTML jako treść - if ( !empty( $cid_to_data_uri ) && isset( $content['html'] ) && trim( $content['html'] ) !== '' ) + // Jeśli jest HTML, zastąp CIDy na URLe załączników i wyczyść style + if ( isset( $content['html'] ) && trim( $content['html'] ) !== '' ) { - $html_with_images = $this -> replaceCidReferences( $content['html'], $cid_to_data_uri ); - $task_text = $this -> prepareImportedTaskTextFromHtml( $html_with_images ); + $html_clean = $content['html']; + if ( !empty( $cid_to_url ) ) + $html_clean = $this -> replaceCidReferences( $html_clean, $cid_to_url ); + + $task_text = $this -> prepareImportedTaskTextFromHtml( $html_clean ); // Zaktualizuj treść zadania $this -> mdb -> update( 'tasks', [ 'text' => $task_text ], [ 'id' => $task_id ] ); @@ -1041,18 +1047,20 @@ class MailToTaskImporter return ''; } - private function convertToDataUri( $content, $mime_type ) + private function guessExtensionFromMime( $mime ) { - $content = (string)$content; - if ( $content === '' ) - return ''; + $map = [ + 'image/jpeg' => 'jpg', + 'image/png' => 'png', + 'image/gif' => 'gif', + 'image/webp' => 'webp', + 'image/bmp' => 'bmp', + 'image/svg+xml' => 'svg', + 'image/tiff' => 'tiff' + ]; - $mime_type = trim( (string)$mime_type ); - if ( $mime_type === '' || $mime_type === 'application/octet-stream' ) - $mime_type = 'image/png'; // Domyślny typ dla obrazów - - $base64 = base64_encode( $content ); - return 'data:' . $mime_type . ';base64,' . $base64; + $mime = strtolower( trim( (string)$mime ) ); + return isset( $map[$mime] ) ? $map[$mime] : 'png'; } private function replaceCidReferences( $html, array $cid_to_url ) @@ -1085,6 +1093,21 @@ class MailToTaskImporter $html = preg_replace( '/]*>.*?<\/blockquote>/is', ' ', $html ); $html = preg_replace( '/]*class="[^"]*(gmail_quote|gmail_signature)[^"]*"[^>]*>.*?<\/div>/is', ' ', $html ); + // Usuń tagi MS Office: , , , itp. + $html = preg_replace( '/<\/?[a-z]+:[^>]*>/is', '', $html ); + + // Usuń xmlns atrybuty + $html = preg_replace( '/\s+xmlns:[a-z]+="[^"]*"/i', '', $html ); + + // Usuń atrybuty class (MsoNormal, itp.) + $html = preg_replace( '/\s+class="[^"]*"/i', '', $html ); + + // Usuń atrybuty style + $html = preg_replace( '/\s+style="[^"]*"/i', '', $html ); + + // Usuń puste paragrafy (z samym   lub spacjami) + $html = preg_replace( '/]*>\s*( |\xC2\xA0)?\s*<\/p>/i', '', $html ); + // Usuń niepotrzebne atrybuty z obrazów (zostaw tylko src, alt, width, height) $html = preg_replace_callback( '/]*)>/i', @@ -1092,16 +1115,8 @@ class MailToTaskImporter $attrs = $matches[1]; $new_attrs = []; - // Wyciągnij ważne atrybuty if ( preg_match( '/\bsrc=["\']([^"\']+)["\']/i', $attrs, $src ) ) - { - // Nie używaj htmlspecialchars dla data URI (Base64), tylko dla zwykłych URLi - $src_value = $src[1]; - if ( strpos( $src_value, 'data:' ) !== 0 ) - $src_value = htmlspecialchars( $src_value, ENT_QUOTES ); - - $new_attrs[] = 'src="' . $src_value . '"'; - } + $new_attrs[] = 'src="' . htmlspecialchars( $src[1], ENT_QUOTES ) . '"'; if ( preg_match( '/\balt=["\']([^"\']+)["\']/i', $attrs, $alt ) ) $new_attrs[] = 'alt="' . htmlspecialchars( $alt[1], ENT_QUOTES ) . '"';