feat: Enhance MailToTaskImporter with inline image support and update task content handling
This commit is contained in:
@@ -1,7 +1,13 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(git log:*)"
|
||||
"Bash(git log:*)",
|
||||
"Bash(git checkout:*)",
|
||||
"Bash(mysql:*)",
|
||||
"Bash(if [ -f logs.txt ])",
|
||||
"Bash(then rm logs.txt)",
|
||||
"Bash(else echo \"Plik logs.txt nie istnieje\")",
|
||||
"Bash(fi)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
12
.vscode/ftp-kr.sync.cache.json
vendored
12
.vscode/ftp-kr.sync.cache.json
vendored
@@ -151,9 +151,9 @@
|
||||
},
|
||||
"config.php": {
|
||||
"type": "-",
|
||||
"size": 1249,
|
||||
"size": 1230,
|
||||
"lmtime": 1770587027872,
|
||||
"modified": false
|
||||
"modified": true
|
||||
},
|
||||
"cron.php": {
|
||||
"type": "-",
|
||||
@@ -204,9 +204,9 @@
|
||||
},
|
||||
"main_view.php": {
|
||||
"type": "-",
|
||||
"size": 42341,
|
||||
"size": 42781,
|
||||
"lmtime": 1770583657535,
|
||||
"modified": false
|
||||
"modified": true
|
||||
},
|
||||
"task_edit.php": {
|
||||
"type": "-",
|
||||
@@ -216,8 +216,8 @@
|
||||
},
|
||||
"task_popup.php": {
|
||||
"type": "-",
|
||||
"size": 11071,
|
||||
"lmtime": 0,
|
||||
"size": 12356,
|
||||
"lmtime": 1770711646996,
|
||||
"modified": false
|
||||
},
|
||||
"task_single.php": {
|
||||
|
||||
@@ -154,7 +154,7 @@ class MailToTaskImporter
|
||||
null,
|
||||
false,
|
||||
'off',
|
||||
false,
|
||||
true,
|
||||
self::TASK_STATUS_ID,
|
||||
'on',
|
||||
0
|
||||
@@ -172,6 +172,30 @@ class MailToTaskImporter
|
||||
continue;
|
||||
}
|
||||
|
||||
// Konwertuj inline images do Base64 i osadź w treści
|
||||
$cid_to_data_uri = [];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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'] ) !== '' )
|
||||
{
|
||||
$html_with_images = $this -> replaceCidReferences( $content['html'], $cid_to_data_uri );
|
||||
$task_text = $this -> prepareImportedTaskTextFromHtml( $html_with_images );
|
||||
|
||||
// Zaktualizuj treść zadania
|
||||
$this -> mdb -> update( 'tasks', [ 'text' => $task_text ], [ 'id' => $task_id ] );
|
||||
}
|
||||
|
||||
// Zapisz normalne załączniki
|
||||
foreach ( $content['attachments'] as $attachment )
|
||||
{
|
||||
$this -> attachments -> uploadFromContent( $task_id, self::TASK_USER_ID, $attachment['name'], $attachment['content'] );
|
||||
@@ -412,9 +436,25 @@ class MailToTaskImporter
|
||||
}
|
||||
|
||||
$cid_refs = $this -> extractReferencedCidValues( $html );
|
||||
|
||||
$attachments = [];
|
||||
$inline_images = [];
|
||||
|
||||
foreach ( $attachment_candidates as $part )
|
||||
{
|
||||
$content_id = isset( $part['content_id'] ) ? (string)$part['content_id'] : '';
|
||||
|
||||
// Sprawdź czy to inline image używany w HTML
|
||||
if ( $content_id !== '' && isset( $cid_refs[$content_id] ) )
|
||||
{
|
||||
$inline_images[$content_id] = [
|
||||
'name' => $part['name'],
|
||||
'content' => $part['body'],
|
||||
'mime' => isset( $part['mime'] ) ? $part['mime'] : 'application/octet-stream'
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !$this -> shouldImportAttachment( $part, $cid_refs ) )
|
||||
continue;
|
||||
|
||||
@@ -429,6 +469,8 @@ class MailToTaskImporter
|
||||
|
||||
return [
|
||||
'text' => $text,
|
||||
'html' => $html,
|
||||
'inline_images' => $inline_images,
|
||||
'attachments' => $attachments
|
||||
];
|
||||
}
|
||||
@@ -616,6 +658,22 @@ class MailToTaskImporter
|
||||
if ( preg_match( '/^\s*--\s*$/', $line_trim ) )
|
||||
break;
|
||||
|
||||
// Polskie stopki
|
||||
if ( preg_match( '/^\s*(Pozdrawiam|Pozdrowienia|Z\s+powa[zż]aniem|Dzi[eę]kuj[eę]|Serdecznie|Miłego\s+dnia)/iu', $line_trim ) )
|
||||
break;
|
||||
|
||||
// Angielskie stopki
|
||||
if ( preg_match( '/^\s*(Best\s+regards|Kind\s+regards|Regards|Sincerely|Thanks|Thank\s+you|Cheers)/i', $line_trim ) )
|
||||
break;
|
||||
|
||||
// Mobilne sygnatury
|
||||
if ( preg_match( '/^\s*Sent\s+from\s+(my\s+)?(iPhone|iPad|Android|Samsung|mobile)/i', $line_trim ) )
|
||||
break;
|
||||
|
||||
// Separatory z podkreślników
|
||||
if ( preg_match( '/^\s*_{3,}\s*$/', $line_trim ) )
|
||||
break;
|
||||
|
||||
$clean[] = $line_trim;
|
||||
}
|
||||
|
||||
@@ -982,4 +1040,90 @@ class MailToTaskImporter
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private function convertToDataUri( $content, $mime_type )
|
||||
{
|
||||
$content = (string)$content;
|
||||
if ( $content === '' )
|
||||
return '';
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
private function replaceCidReferences( $html, array $cid_to_url )
|
||||
{
|
||||
if ( trim( (string)$html ) === '' || empty( $cid_to_url ) )
|
||||
return $html;
|
||||
|
||||
foreach ( $cid_to_url as $cid => $url )
|
||||
{
|
||||
// Zastąp wszystkie odniesienia do tego CID
|
||||
$html = preg_replace(
|
||||
'/(<img[^>]+src=["\'])cid:' . preg_quote( $cid, '/' ) . '(["\'][^>]*>)/i',
|
||||
'$1' . $url . '$2',
|
||||
$html
|
||||
);
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function prepareImportedTaskTextFromHtml( $html )
|
||||
{
|
||||
$html = trim( (string)$html );
|
||||
if ( $html === '' )
|
||||
return '(brak tresci)';
|
||||
|
||||
// Usuń niepotrzebne elementy (style, script, blockquote)
|
||||
$html = preg_replace( '/<style\b[^>]*>.*?<\/style>/is', ' ', $html );
|
||||
$html = preg_replace( '/<script\b[^>]*>.*?<\/script>/is', ' ', $html );
|
||||
$html = preg_replace( '/<blockquote\b[^>]*>.*?<\/blockquote>/is', ' ', $html );
|
||||
$html = preg_replace( '/<div[^>]*class="[^"]*(gmail_quote|gmail_signature)[^"]*"[^>]*>.*?<\/div>/is', ' ', $html );
|
||||
|
||||
// Usuń niepotrzebne atrybuty z obrazów (zostaw tylko src, alt, width, height)
|
||||
$html = preg_replace_callback(
|
||||
'/<img([^>]*)>/i',
|
||||
function( $matches ) {
|
||||
$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 . '"';
|
||||
}
|
||||
|
||||
if ( preg_match( '/\balt=["\']([^"\']+)["\']/i', $attrs, $alt ) )
|
||||
$new_attrs[] = 'alt="' . htmlspecialchars( $alt[1], ENT_QUOTES ) . '"';
|
||||
|
||||
if ( preg_match( '/\bwidth=["\']?(\d+)["\']?/i', $attrs, $width ) )
|
||||
$new_attrs[] = 'width="' . (int)$width[1] . '"';
|
||||
|
||||
if ( preg_match( '/\bheight=["\']?(\d+)["\']?/i', $attrs, $height ) )
|
||||
$new_attrs[] = 'height="' . (int)$height[1] . '"';
|
||||
|
||||
return '<img ' . implode( ' ', $new_attrs ) . '>';
|
||||
},
|
||||
$html
|
||||
);
|
||||
|
||||
// Wyczyść HTML z nadmiarowych białych znaków
|
||||
$html = preg_replace( '/\s+/', ' ', $html );
|
||||
$html = trim( $html );
|
||||
|
||||
if ( $html === '' )
|
||||
return '(brak tresci)';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,7 +224,8 @@ class TaskAttachmentRepository
|
||||
if ( !$insert )
|
||||
return [ 'status' => 'error', 'msg' => 'Nie udalo sie zapisac zalacznika w bazie.' ];
|
||||
|
||||
return [ 'status' => 'success' ];
|
||||
$attachment_id = $this -> mdb -> id();
|
||||
return [ 'status' => 'success', 'id' => (int)$attachment_id, 'relative_path' => $relative_path, 'stored_name' => $stored_name ];
|
||||
}
|
||||
|
||||
private function buildPublicUrl( $relative_path, $stored_name )
|
||||
|
||||
@@ -21,5 +21,5 @@ $settings['tasks_auto_start_timer'] = false;
|
||||
|
||||
// OpenAI ChatGPT API configuration for email task parsing
|
||||
$settings['openai_api_key'] = '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'; // Wklej tutaj swój klucz API OpenAI
|
||||
$settings['openai_parse_emails'] = true; // true = użyj AI do parsowania emaili, false = normalne parsowanie
|
||||
$settings['openai_parse_emails'] = false; // true = użyj AI do parsowania emaili, false = normalne parsowanie
|
||||
$settings['openai_model'] = 'gpt-4o-mini'; // Model: gpt-4o-mini, gpt-4o, gpt-5-nano, itp.
|
||||
|
||||
@@ -27,7 +27,10 @@ if ( $this -> params['label'] )
|
||||
if ( $this -> params['placeholder'] )
|
||||
$out .= 'placeholder="' . $this -> params['placeholder'] . '" ';
|
||||
|
||||
$out .= ' rows="' . $this -> params['rows'] . '">' . $this -> secureHTML( $this -> params['value'] ) . '</textarea>';
|
||||
if ( isset( $this -> params['skip_encoding'] ) && $this -> params['skip_encoding'] )
|
||||
$out .= ' rows="' . $this -> params['rows'] . '">' . $this -> params['value'] . '</textarea>';
|
||||
else
|
||||
$out .= ' rows="' . $this -> params['rows'] . '">' . $this -> secureHTML( $this -> params['value'] ) . '</textarea>';
|
||||
|
||||
if ( $this -> params['label'] )
|
||||
{
|
||||
|
||||
@@ -22,7 +22,8 @@ ob_start();
|
||||
'name' => 'text',
|
||||
'id' => 'text',
|
||||
'value' => $this -> task[ 'text' ],
|
||||
'rows' => 10
|
||||
'rows' => 10,
|
||||
'skip_encoding' => true
|
||||
]
|
||||
);
|
||||
?>
|
||||
|
||||
@@ -22,7 +22,8 @@ ob_start();
|
||||
'name' => 'text',
|
||||
'id' => 'text',
|
||||
'value' => $this -> task[ 'text' ],
|
||||
'rows' => 10
|
||||
'rows' => 10,
|
||||
'skip_encoding' => true
|
||||
]
|
||||
);
|
||||
?>
|
||||
|
||||
Reference in New Issue
Block a user