From 5be2152e89b8ff8f77734d057e8bbbf015faedb0 Mon Sep 17 00:00:00 2001 From: Brian Read Date: Mon, 17 Mar 2025 12:08:40 +0000 Subject: [PATCH] * Mon Mar 17 2025 Brian Read 11.0.0-67.sme - re-write qmailanalog for postfix [SME: 12951] - Clean up backup.pm - Enhance module panel - used by mail log analysis and Licence display --- .../smanager/lib/SrvMngr/Controller/Backup.pm | 122 ++++++- .../lib/SrvMngr/Controller/Qmailanalog.pm | 330 +++++++++++++++--- .../I18N/Modules/General/general_en.lex | 2 +- .../Modules/Qmailanalog/qmailanalog_en.lex | 15 +- .../themes/default/public/css/module.css | 43 +++ .../themes/default/public/js/qmailanalog.js | 25 ++ .../themes/default/templates/module.html.ep | 31 +- .../default/templates/qmailanalog.html.ep | 39 ++- 8 files changed, 523 insertions(+), 84 deletions(-) create mode 100644 root/usr/share/smanager/themes/default/public/css/module.css create mode 100644 root/usr/share/smanager/themes/default/public/js/qmailanalog.js diff --git a/root/usr/share/smanager/lib/SrvMngr/Controller/Backup.pm b/root/usr/share/smanager/lib/SrvMngr/Controller/Backup.pm index 54465b8..d7f46ea 100644 --- a/root/usr/share/smanager/lib/SrvMngr/Controller/Backup.pm +++ b/root/usr/share/smanager/lib/SrvMngr/Controller/Backup.pm @@ -32,6 +32,10 @@ use esmith::util; use esmith::lockfile; use esmith::BlockDevices; use constant DEBUG => $ENV{MOJO_SMANAGER_DEBUG} || 0; + +use constant FALSE => 0; +use constant TRUE => 1; + #our $cdb = esmith::ConfigDB->open || die "Couldn't open config db"; #remove as cached gives problems #our $adb = esmith::AccountsDB->open || die "Couldn't open accounts db"; #our $rdb = esmith::ConfigDB->open('/etc/e-smith/restore') || die "Couldn't open restore db"; @@ -932,7 +936,7 @@ sub workstnVerify { sub workstnRestore { my ($c) = @_; - my $out; + my $out = ''; my $restoreref = $c->param('Backupset'); my $set = $restoreref; $set =~ s/\/[^\/]*$//; @@ -1015,6 +1019,7 @@ sub workstnRestore { return "$c->l('bac_OPERATION_STATUS_REPORT') $c->l('bac_ERR_PRE_RESTORE')"; } $| = 1; + my $RD; if (open(RD, "-|")) { @@ -1047,8 +1052,8 @@ sub workstnRestore { or warn($c->l('bac_ERR_RESTORING_INITIAL_GRP') . "\n"); esmith::util::backgroundCommand(0, "/sbin/e-smith/signal-event", "post-upgrade"); - # system("/sbin/e-smith/signal-event", "post-upgrade") == 0 - # or die ($c->l('bac_ERROR_UPDATING_CONFIGURATION')."\n"); + #system("/sbin/e-smith/signal-event", "post-upgrade") == 0 + # or die ($c->l('bac_ERROR_UPDATING_CONFIGURATION')."\n"); } else { $message = $c->l('bac_RESTORE_FAILED'); } @@ -1076,9 +1081,111 @@ sub workstnRestore { die($error_message) if $error_message; exit(0); } ## end else [ if (open(RD, "-|")) ] - $rdb->reload; - $error_message .= $c->bunmount($mntdir, $VFSType); - return '#OK#' . $out; + + #my $RD; + + ## Fork-safe open with explicit error handling + #unless (open($RD, "-|")) { + ## Child process + #local $SIG{__DIE__} = sub { exit 255 }; + #$| = 1; # Autoflush + + #eval { + #foreach my $file (@restorefiles) { + ## Security: strict filename validation + #unless ($file =~ m{^[\w\/.-]+$}) { + #die "Invalid filename: $file"; + #} + + ## Check file existence + #unless (-e $file) { + #die "Backup file $file does not exist"; + #} + + ## Execute dar with error checking + #system("/usr/bin/dar", "-Q", "-x", $file, "-v", "-N", "-R", "/", "-wa"); + #if ($? == -1) { + #die "Failed to execute dar: $!"; + #} elsif ($? & 127) { + #die sprintf("dar died with signal %d, %s coredump", + #($? & 127), ($? & 128) ? 'with' : 'without'); + #} elsif ($? >> 8 != 0) { + #die "dar exited with error code " . ($? >> 8); + #} + #} + + ## Unmount with error checking + #if (my $unmount_err = $c->bunmount($mntdir, $VFSType)) { + #die "Unmount failed: $unmount_err"; + #} + #}; + + #if (my $child_err = $@) { + #print STDERR "CHILD ERROR: $child_err"; + #exit 254; + #} + #exit 0; + #} + #else { + ## Parent process + #eval { + ## Verify fork succeeded + #unless (defined $RD) { + #die "Fork failed: $!"; + #} + + #$out .= $c->l('bac_FILES_HAVE_BEEN_RESTORED') . "\n"; + + ## Close pipe and check status + #unless (close $RD) { + #die "Pipe close failed: $!"; + #} + + #my $child_status = $?; + #if ($child_status != 0) { + #die "Child process failed with status " . ($child_status >> 8); + #} + + ## Post-restore actions + #if ($complete) { + #system("/usr/sbin/groupmod", "-g", $www_gid, "www"); + #if ($? != 0) { + #die $c->l('bac_ERR_RESTORING_GID') . ": $! (status $?)"; + #} + + #system("/usr/sbin/usermod", "-g", $www_gid, "www"); + #if ($? != 0) { + #die $c->l('bac_ERR_RESTORING_INITIAL_GRP') . ": $! (status $?)"; + #} + + #my $bg_result = esmith::util::backgroundCommand(0, "/sbin/e-smith/signal-event", "post-upgrade"); + #unless ($bg_result) { + #die "Failed to schedule post-upgrade event"; + #} + #} else { + #die $c->l('bac_RESTORE_FAILED'); + #} + #}; + + ## Error handling + #if (my $err = $@) { + #$rec->set_prop('state', 'failed'); + #$rec->set_prop('error', "$err"); + #esmith::lockfile::UnlockFile($file_handle); + #return $c->l('bac_RESTORE_FAILED_MSG') . ": $err"; + #} + #} + $rdb->reload; + $error_message .= $c->bunmount($mntdir, $VFSType); + return '#OK#' . $out; } ## end sub workstnRestore sub workstnSelRestore() { @@ -1455,6 +1562,7 @@ sub performReboot { #print "$c->l('bac_SERVER_REBOOT')"; #print "$c->l('bac_SERVER_WILL_REBOOT')"; + warn "reboot coming"; esmith::util::backgroundCommand(2, "/sbin/e-smith/signal-event", "reboot"); return "#OK#" . $c->l('bac_SERVER_WILL_REBOOT'); } ## end sub performReboot @@ -1985,7 +2093,7 @@ sub bunmount { system('/bin/umount', '-f', $mount) == 0 or return ($c->l('bac_ERR_WHILE_UNMOUNTING')); } - return; + return ""; } ## end sub bunmount sub findmnt { diff --git a/root/usr/share/smanager/lib/SrvMngr/Controller/Qmailanalog.pm b/root/usr/share/smanager/lib/SrvMngr/Controller/Qmailanalog.pm index 6e4faa1..61cfa90 100644 --- a/root/usr/share/smanager/lib/SrvMngr/Controller/Qmailanalog.pm +++ b/root/usr/share/smanager/lib/SrvMngr/Controller/Qmailanalog.pm @@ -14,6 +14,9 @@ use SrvMngr qw(gen_locale_date_string); use Locale::gettext; use SrvMngr::I18N; use SrvMngr qw(theme_list init_session); +use List::Util qw(sum); + +#use Mail::Log::Trace::Postfix; sub main { my $c = shift; @@ -48,44 +51,63 @@ sub generateReport { my $c = shift; my $report_type = shift; my $out = ''; - #------------------------------------------------------------ - # Looks good; go ahead and generate the report. + # Go ahead and generate the report. #------------------------------------------------------------ - # $| = 1; my $now_string = $c->gen_locale_date_string(); + my $log_path = '/var/log/maillog'; $out .= sprintf("

%s %s

", $c->l('REPORT_GENERATED'), $now_string); - - if ($report_type =~ /^qmail-q/) { - open(QMAILQUEUEREPORT, "/var/qmail/bin/$report_type |"); - $out .= sprintf "
";
-
-        while () {
-            $out .= sprintf("%s", $_);
-        }
-        close QMAILQUEUEREPORT;
-        $out .= sprintf "
"; - $out .= sprintf("

%s

", $c->l('END_OF_REPORT')); - return ''; - } ## end if ($report_type =~ /^qmail-q/) - chdir "/var/log/qmail"; - open(QMAILANALOG, - "/bin/cat \@* current 2>/dev/null" - . "| /usr/local/bin/tai64nunix" - . "| /usr/local/qmailanalog/bin/matchup 5>/dev/null" - . "| /usr/local/qmailanalog/bin/$report_type |"); $out .= sprintf "
";
+    # Get the selected report from the form submission
+    my $selected_report = $report_type;
 
-    while () {
+    # Call the relevant report sub based on the selection
+    if ($selected_report eq 'daily_summary') {
+        $out .= daily_summary_report($log_path);  
+    }
+    elsif ($selected_report eq 'daily_summary_today') {
+        $out .= daily_summary_report_today($log_path);  
+    }
+    elsif ($selected_report eq 'top_senders') {
+        $out .= top_senders_and_recipients($log_path);  
+    }
+    elsif ($selected_report eq 'bounce_analysis') {
+        $out .= bounce_rate_analysis($log_path);  
+    }
+    elsif ($selected_report eq 'spam_and_virus') {
+        $out .= spam_and_virus_filter_report($log_path);  
+    }
+    elsif ($selected_report eq 'delivery_status') {
+        $out .= delivery_status_report($log_path);  
+    }
+    elsif ($selected_report eq 'geo_analysis') {
+        $out .= geographical_analysis_of_email($log_path);  
+    }
+    elsif ($selected_report eq 'traffic_analysis') {
+        $out .= traffic_analysis($log_path);  
+    }
+    elsif ($selected_report eq 'auth_analysis') {
+        $out .= authentication_analysis($log_path);  
+    }
+    elsif ($selected_report eq 'user_activity') {
+        $out .= user_activity_report($log_path);  
+    }
+    elsif ($selected_report eq 'error_reporting') {
+        $out .= error_reporting($log_path);  
+    }
+    elsif ($selected_report eq 'comparison_reports') {
+        $out .= comparison_reports($log_path, '/var/log/mail.log.1');
+    }
+    elsif ($selected_report eq 'customized_reports') {
+        $out .= customized_reports($log_path);  
+    }
+    else {
+        $out .= 'Invalid report selected';
+    }
 
-        # Cook any special HTML characters
-        s/\&/\&/g;
-        s/\"/\"/g;
-        s/\>/\>/g;
-        s/\)
-    close QMAILANALOG;
+    # The $output variable now contains the generated report output.
+    # Further processing can be done here, or you can render it later.
+  
     $out .= sprintf "
"; $out .= sprintf("

%s

", $c->l('END_OF_REPORT')); return $out; @@ -94,22 +116,236 @@ sub generateReport { sub reportType_list { my $c = shift; my @array = ( - - # [ $c->l('qma_LIST_OUTGOING') => 'qmail-qread' ], - # [ $c->l('qma_SUMMARIZE_QUEUE') => 'qmail-qstat' ], - [ $c->l('qma_SUCCESSFUL_DELIVERY_DELAY') => 'zddist' ], - [ $c->l('qma_REASONS_DEFERRAL') => 'zdeferrals' ], - [ $c->l('qma_REASONS_FAILURE') => 'zfailures' ], - [ $c->l('qma_BASIC_STATS') => 'zoverall' ], - [ $c->l('qma_RECIP_STATS') => 'zrecipients' ], - [ $c->l('qma_RECIP_HOSTS') => 'zrhosts' ], - [ $c->l('qma_RECIP_ORDERED') => 'zrxdelay' ], - [ $c->l('qma_SENDER_STATS') => 'zsenders' ], - [ $c->l('qma_SENDMAIL_STYLE') => 'zsendmail' ], - [ $c->l('qma_REASONS_SUCCESS') => 'zsuccesses' ], - [ $c->l('qma_SENDER_UIDS') => 'zsuids' ] - ); + [$c->l('qma_Daily_Summary_Report_yesterday') => 'daily_summary'], + [$c->l('qma_Daily_Summary_Report_today') => 'daily_summary_today'], + #[$c->l('qma_Top Senders and Recipients') => 'top_senders'], + #[$c->l('qma_Bounce Rate Analysis') => 'bounce_analysis'], + #[$c->l('qma_Spam and Virus Filtering Report') => 'spam_and_virus'], + #[$c->l('qma_Delivery Status Report') => 'delivery_status'], + #[$c->l('qma_Geographic Analysis of Email') => 'geo_analysis'], + #[$c->l('qma_Traffic Analysis') => 'traffic_analysis'], + #[$c->l('qma_Authentication Analysis') => 'auth_analysis'], + #[$c->l('qma_User Activity Report') => 'user_activity'], + #[$c->l('qma_Error Reporting') => 'error_reporting'], + #[$c->l('qma_Comparison Reports') => 'comparison_reports'], + #[$c->l('qma_Customized Reports') => 'customized_reports'], + ); my @sorted_array = sort { $a->[0] cmp $b->[0] } @array; return \@sorted_array; } ## end sub reportType_list -1; + +sub daily_summary_report { + my $log_file = shift; # Path to log file + my $output = qx(ls -1 /var/log/maillog* | xargs cat |pflogsumm -d yesterday --detail 0 --no-no-msg-size); + return format_as_html("Daily Summary Report", $output); +} + +sub daily_summary_report_today { + my $log_file = shift; # Path to log file + my $output = qx(ls -1 /var/log/maillog* | xargs cat |pflogsumm -d today --detail 0 --no-no-msg-size); + return format_as_html("Daily Summary Report", $output); +} + +sub top_senders_and_recipients { + my $log_file = shift; + my $output = qx(pflogsumm --smtpd-stats $log_file); + return format_as_html("Top Senders and Recipients", $output); +} + +sub bounce_rate_analysis { + my $log_file = shift; + my $output = qx(pflogsumm --bounce-detail 10 $log_file); # Show up to 10 bounce details + return format_as_html("Bounce Rate Analysis", $output); +} + +sub spam_and_virus_filter_report { + my $log_file = shift; + my $output = qx(pflogsumm -u 10 $log_file); # User report with up to 10 entries + return format_as_html("Spam and Virus Filtering Report", $output); +} + +sub delivery_status_report { + my $log_file = shift; + my $output = qx(pflogsumm --deferral-detail 10 $log_file); # Show deferral details + return format_as_html("Delivery Status Report", $output); +} + +sub geographical_analysis_of_email { + my $log_file = shift; + # `pflogsumm` doesn't have a specific option for geographic analysis in the help text; + # It's assumed this could be replaced with something relevant, like a SMTP detail. + my $output = qx(pflogsumm --smtp-detail 10 $log_file); # Show up to 10 SMTP details + return format_as_html("Geographic Analysis of Email", $output); +} + +sub traffic_analysis { + my $log_file = shift; + my $output = qx(pflogsumm --verbose-msg-detail $log_file); # Request verbose detail + return format_as_html("Traffic Analysis", $output); +} + +sub authentication_analysis { + my $log_file = shift; + my $output = qx(pflogsumm -u 10 --verbose-msg-detail $log_file); # User detailed report + return format_as_html("Authentication Analysis", $output); +} + +sub user_activity_report { + my $log_file = shift; + my $output = qx(pflogsumm -u 20 $log_file); # Show user activity for up to 20 users + return format_as_html("User Activity Report", $output); +} + +sub error_reporting { + my $log_file = shift; + my $output = qx(pflogsumm --problems-first $log_file); # This will show problems first + return format_as_html("Error Reporting", $output); +} + +sub comparison_reports { + my ($log_file1, $log_file2) = @_; # Comparing two log files + my $output = qx(pflogsumm $log_file1 $log_file2); # Standard comparison without special flags + return format_as_html("Comparison Reports", $output); +} + +sub customized_reports { + my $log_file = shift; + # Because we don't have a concrete custom flag, we'll consider using -d with specific detail. + my $output = qx(pflogsumm --detail 10 $log_file); # Generally show detailed summary + return format_as_html("Customized Reports", $output); +} + +sub format_as_html { + my ($title, $content) = @_; + return <$title +
$content
+HTML +} + + +### 1. Message Tracking +#sub trace_message { + #my ($log_path, $message_id) = @_; + ##my $tracer = Mail::Log::Trace::Postfix->new({log_file => $log_path}); + ##$tracer->set_message_id($message_id); + + #my $output = "Message Tracking Report for ID: $message_id\n"; + ##$output .= "=" x 50 . "\n"; + ##$output .= sprintf "%-12s: %s\n", 'From', $tracer->get_from_address; + ##$output .= sprintf "%-12s: %s\n", 'Status', $tracer->get_final_status; + + ##$output .= "\nRecipients:\n"; + ##$output .= join("\n", map { "- $_" } $tracer->get_recipient_addresses); + + ##$output .= "\n\nTimeline:\n"; + ##my $timeline = $tracer->get_timestamps; + ##while (my ($stage, $time) = each %$timeline) { + ##$output .= sprintf "%-10s: %s\n", ucfirst($stage), $time; + ##} + + #return $output || "No records found for message ID: $message_id"; +#} + +#### 2. Queue Analysis +#sub get_queue_stats { + #my $spool_dir = '/var/spool/postfix'; + #my %queues = map { $_ => 0 } qw(active deferred bounce hold corrupt); + + #foreach my $q (keys %queues) { + #opendir(my $dh, "$spool_dir/$q"); + #$queues{$q} = scalar(grep { -f "$spool_dir/$q/$_" } readdir($dh)); + #closedir($dh); + #} + + #my $output = "Current Postfix Queue Status\n"; + #$output .= "=" x 30 . "\n"; + #$output .= sprintf "%-10s: %3d messages\n", ucfirst($_), $queues{$_} + #for sort keys %queues; + #$output .= "\nTotal: " . sum(values %queues) . " messages in queue"; + + #return $output; +#} + +#### 3. Message Statistics +#sub get_message_stats { + #my ($log_path) = @_; + #my %stats = (received => 0, rejected => 0, delivered => 0, + #deferred => 0, bounced => 0, held => 0); + + #open(my $fh, '<', $log_path); + #while(<$fh>) { + #$stats{received}++ if /qmgr.*: [A-Z0-9]+: from=/; + #$stats{delivered}++ if /status=sent/; + #$stats{rejected}++ if /NOQUEUE: reject/; + #$stats{deferred}++ if /status=deferred/; + #$stats{bounced}++ if /status=bounced/; + #$stats{held}++ if /status=hold/; + #} + #close($fh); + + #my $output = "Message Statistics for " . localtime . "\n"; + #$output .= "=" x 40 . "\n"; + #$output .= sprintf "%-12s: %6d\n", 'Received', $stats{received}; + #$output .= sprintf "%-12s: %6d (%.1f%%)\n", 'Delivered', $stats{delivered}, + #($stats{received} ? ($stats{delivered}/$stats{received}*100) : 0); + #$output .= sprintf "%-12s: %6d\n", 'Rejected', $stats{rejected}; + #$output .= sprintf "%-12s: %6d\n", 'Deferred', $stats{deferred}; + #$output .= sprintf "%-12s: %6d\n", 'Bounced', $stats{bounced}; + #$output .= sprintf "%-12s: %6d\n", 'Held', $stats{held}; + + #return $output; +#} + +#### 4. User Activity Audit +#sub get_user_activity { + #my ($log_path, $email) = @_; + ##my $tracer = Mail::Log::Trace::Postfix->new({log_file => $log_path}); + + ##my $sent = scalar $tracer->find_messages_by_sender($email); + ##my $received = scalar $tracer->find_messages_by_recipient($email); + + #my $output = "Activity Report for: $email\n"; + ##$output .= "=" x (length($email) + 18) . "\n"; + ##$output .= "Messages sent: $sent\n"; + ##$output .= "Messages received: $received\n\n"; + + ##$output .= "Last week's activity:\n"; + ##$output .= join("\n", map { sprintf "- %s: %d messages", $_->[0], $_->[1] } + ##$tracer->get_weekly_stats($email)); + + #return $output || "No activity found for $email"; +#} + +#### 5. Security Monitoring +#sub detect_auth_failures { + #my ($log_path) = @_; + #my %failures; + + #open(my $fh, '<', $log_path); + #while(<$fh>) { + #if(/SASL (?:LOGIN|PLAIN) authentication failed.*?\[([0-9.]+)\]/) { + #$failures{$1}++; + #} + #} + #close($fh); + + #return "No authentication failures found" unless keys %failures; + + #my $output = "Authentication Failure Report\n"; + #$output .= "=" x 30 . "\n"; + #$output .= sprintf "%-15s %s\n", 'IP Address', 'Attempts'; + #$output .= sprintf "%-15s %s\n", '-' x 15, '-' x 7; + + #foreach my $ip (sort { $failures{$b} <=> $failures{$a} } keys %failures) { + #$output .= sprintf "%-15s %5d\n", $ip, $failures{$ip}; + #} + #$output .= "\nTotal failures: " . sum(values %failures); + + #return $output; +#} + + + + +1; \ No newline at end of file diff --git a/root/usr/share/smanager/lib/SrvMngr/I18N/Modules/General/general_en.lex b/root/usr/share/smanager/lib/SrvMngr/I18N/Modules/General/general_en.lex index a372ee7..9d8e0a4 100644 --- a/root/usr/share/smanager/lib/SrvMngr/I18N/Modules/General/general_en.lex +++ b/root/usr/share/smanager/lib/SrvMngr/I18N/Modules/General/general_en.lex @@ -151,4 +151,4 @@ SMALL => 'Small', MEDIUM => 'Medium', LARGE => 'Large', FIELD_INVALID_CHARS => 'A field you entered contains invalid characters.', - +'REPORT_GENERATED' => "Report generated", \ No newline at end of file diff --git a/root/usr/share/smanager/lib/SrvMngr/I18N/Modules/Qmailanalog/qmailanalog_en.lex b/root/usr/share/smanager/lib/SrvMngr/I18N/Modules/Qmailanalog/qmailanalog_en.lex index b3f5cbf..462b7e6 100644 --- a/root/usr/share/smanager/lib/SrvMngr/I18N/Modules/Qmailanalog/qmailanalog_en.lex +++ b/root/usr/share/smanager/lib/SrvMngr/I18N/Modules/Qmailanalog/qmailanalog_en.lex @@ -8,6 +8,14 @@ reports are available.

these reports

', 'qma_REPORT_TYPE' => 'Choose a report type', 'qma_GENERATE_REPORT' => 'Generate report', +'qma_INVALID_REPORT_TYPE' => 'Invalid report type: ', +'qma_REPORT_GENERATED' => 'Report generated: ', +'qma_END_OF_REPORT' => 'End of Report', +'Mail log file analysis' => 'Mail log file analysis', + +'qma_Daily_Summary_Report_yesterday' => 'Summary report for yesterday', +'qma_Daily_Summary_Report_today' => 'Summary report for today up to now', + 'qma_LIST_OUTGOING' => 'List outgoing messages and recipients', 'qma_SUMMARIZE_QUEUE' => 'Summarize status of mail queue', 'qma_SUCCESSFUL_DELIVERY_DELAY' => 'Successful delivery delay distribution', @@ -20,9 +28,4 @@ these reports

', 'qma_SENDER_STATS' => 'Sender statistics', 'qma_SENDMAIL_STYLE' => 'Sendmail style log', 'qma_REASONS_SUCCESS' => 'Reasons for success', -'qma_SENDER_UIDS' => 'Sender uids', -'qma_INVALID_REPORT_TYPE' => 'Invalid report type: ', -'qma_REPORT_GENERATED' => 'Report generated: ', -'qma_END_OF_REPORT' => 'End of Report', -'Mail log file analysis' => 'Mail log file analysis', - +'qma_SENDER_UIDS' => 'Sender uids', \ No newline at end of file diff --git a/root/usr/share/smanager/themes/default/public/css/module.css b/root/usr/share/smanager/themes/default/public/css/module.css new file mode 100644 index 0000000..f4f77d8 --- /dev/null +++ b/root/usr/share/smanager/themes/default/public/css/module.css @@ -0,0 +1,43 @@ +/* General styles for the module panel */ +#module { + padding: 20px; + border: 1px solid #ccc; + border-radius: 10px; + background-color: #f9f9f9; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +/* Debug information styling */ +#module p { + font-family: monospace; + color: #555; +} + +#module pre { + background-color: #eee; + padding: 10px; + border-radius: 5px; +} + +/* Error message styling */ +.sme-error { + color: #d9534f; + font-weight: bold; + margin-bottom: 15px; +} + +/* Title styling */ +#module h1 { + font-family: Arial, sans-serif; + color: #333; + text-align: center; + margin-bottom: 20px; +} + +/* Content styling */ +.module-content { + font-family: Georgia, serif; + font-size: 13px; + line-height: 1.2; + color: #555; +} \ No newline at end of file diff --git a/root/usr/share/smanager/themes/default/public/js/qmailanalog.js b/root/usr/share/smanager/themes/default/public/js/qmailanalog.js new file mode 100644 index 0000000..edcb9f5 --- /dev/null +++ b/root/usr/share/smanager/themes/default/public/js/qmailanalog.js @@ -0,0 +1,25 @@ +document.addEventListener('DOMContentLoaded', function() { + const analysisType = document.getElementById('analysis_type'); + const messageIdGroup = document.getElementById('message_id_group'); + const emailAddressGroup = document.getElementById('email_address_group'); + + // Initially hide both controls + messageIdGroup.style.display = 'none'; + emailAddressGroup.style.display = 'none'; + + analysisType.addEventListener('change', function() { + // Hide both controls first + messageIdGroup.style.display = 'none'; + emailAddressGroup.style.display = 'none'; + + // Show the relevant control based on the selected option + switch(this.value) { + case 'trace_message': + messageIdGroup.style.display = 'block'; + break; + case 'user_activity': + emailAddressGroup.style.display = 'block'; + break; + } + }); +}); \ No newline at end of file diff --git a/root/usr/share/smanager/themes/default/templates/module.html.ep b/root/usr/share/smanager/themes/default/templates/module.html.ep index 9eef738..01789e3 100644 --- a/root/usr/share/smanager/themes/default/templates/module.html.ep +++ b/root/usr/share/smanager/themes/default/templates/module.html.ep @@ -1,20 +1,27 @@ % layout 'default', title => "Sme server 2 - module"; % content_for 'module' => begin - +%= stylesheet '/css/module.css'
% if (config->{debug} == 1) { -

- %= dumper $c->current_route -

+

+ Debug Info: +

<%= dumper $c->current_route %>
+

% } - % if ( stash 'error' ) { -
- %= $c->render_to_string(inline => stash 'error') -
- %} -

<%=$title %>


- %= $c->render_to_string( inline => stash 'modul' ) + + % if (stash 'error') { +
+ Error:
+ <%= $c->render_to_string(inline => stash 'error') %> +
+ % } + +

<%= $title %>

+ +
+ <%= $c->render_to_string(inline => stash 'modul') %> +
-%end \ No newline at end of file +% end \ No newline at end of file diff --git a/root/usr/share/smanager/themes/default/templates/qmailanalog.html.ep b/root/usr/share/smanager/themes/default/templates/qmailanalog.html.ep index 8ae5edb..de9122d 100644 --- a/root/usr/share/smanager/themes/default/templates/qmailanalog.html.ep +++ b/root/usr/share/smanager/themes/default/templates/qmailanalog.html.ep @@ -1,6 +1,6 @@ % layout 'default', title => "Sme server 2 - qmailanalog"; - % content_for 'module' => begin +%= javascript '/js/qmailanalog.js'
%if (config->{debug} == 1) {

@@ -11,17 +11,34 @@
<%= $modul %> <% my $btn = l('qma_GENERATE_REPORT'); %> - %= form_for 'qmailanalog' => (method => 'POST') => begin -

- - %=l 'qma_REPORT_TYPE' - - - %= select_field 'report_type' => $c->reportType_list() - -

- %= submit_button "$btn", class => 'action' +

+ + %=l 'qma_REPORT_TYPE' + + + %= select_field 'report_type' => $c->reportType_list(), id => 'analysis_type' + +

+ + +
+ + %= label_for message_id => 'Message ID:' + + %= text_field 'message_id', placeholder => 'Enter Postfix Message ID', id => 'message_id_group' + +
+ +
+ + %= label_for email_address => 'Email Address:' + + %= email_field 'email_address', placeholder => 'Enter email address', id => 'email_address_group' + +
+ + %= submit_button "$btn", class => 'action' % end
%end \ No newline at end of file