cloudlog/application/controllers/Monthlyreport.php
Peter Goodhall 45528ee293 Add new gridsquares by band to monthly report
Introduces per-band breakdown of new gridsquares in the monthly report, including model, controller, and view changes. The report now displays new gridsquares grouped by band, as well as improved details for new DXCCs and satellite activity breakdowns.
2025-11-14 17:49:25 +00:00

349 lines
12 KiB
PHP

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
Controller for generating monthly reports of amateur radio activity
*/
class Monthlyreport extends CI_Controller {
function __construct()
{
parent::__construct();
$this->load->helper(array('form', 'url'));
$this->load->model('user_model');
if(!$this->user_model->authorize(2)) {
$this->session->set_flashdata('notice', 'You\'re not allowed to do that!');
redirect('dashboard');
}
}
/**
* Index page - display report selection form
*/
public function index()
{
$this->load->model('logbooks_model');
$data['logbooks'] = $this->logbooks_model->show_all();
$data['page_title'] = "Monthly Report";
$this->load->view('interface_assets/header', $data);
$this->load->view('monthlyreport/index');
$this->load->view('interface_assets/footer');
}
/**
* Generate report for selected logbook and month
*/
public function generate()
{
$this->load->model('monthlyreport_model');
$this->load->model('logbooks_model');
// Get parameters from POST
$logbook_id = $this->input->post('logbook_id');
$year = $this->input->post('year');
$month = $this->input->post('month');
// Validate inputs
if (empty($logbook_id) || empty($year) || empty($month)) {
$this->session->set_flashdata('notice', 'Please select a logbook and month');
redirect('monthlyreport');
}
// Get logbook relationships (station locations)
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id);
if (!$logbooks_locations_array) {
$this->session->set_flashdata('notice', 'No station locations found for this logbook');
redirect('monthlyreport');
}
// Generate report data
$data['report'] = $this->monthlyreport_model->generate_report($logbooks_locations_array, $year, $month);
$data['logbook_name'] = $this->logbooks_model->find_name($logbook_id);
$data['year'] = $year;
$data['month'] = $month;
$data['month_name'] = date('F', mktime(0, 0, 0, $month, 1));
$data['page_title'] = "Monthly Report - " . $data['month_name'] . " " . $year;
$this->load->view('interface_assets/header', $data);
$this->load->view('monthlyreport/report');
$this->load->view('interface_assets/footer');
}
/**
* Export report in AI-friendly format (JSON)
*/
public function export_json()
{
$this->load->model('monthlyreport_model');
$this->load->model('logbooks_model');
// Get parameters from POST
$logbook_id = $this->input->post('logbook_id');
$year = $this->input->post('year');
$month = $this->input->post('month');
// Get logbook relationships
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id);
// Generate report data
$report = $this->monthlyreport_model->generate_report($logbooks_locations_array, $year, $month);
$logbook_name = $this->logbooks_model->find_name($logbook_id);
$month_name = date('F', mktime(0, 0, 0, $month, 1));
// Create AI-friendly export
$export = array(
'metadata' => array(
'logbook' => $logbook_name,
'period' => $month_name . ' ' . $year,
'generated_at' => date('Y-m-d H:i:s'),
'report_type' => 'monthly_amateur_radio_activity'
),
'summary' => array(
'total_qsos' => $report['total_qsos'],
'new_dxcc_entities' => count($report['new_dxcc']),
'new_dxcc_by_band_count' => count($report['new_dxcc_by_band']),
'new_dxcc_satellite' => count($report['new_dxcc_satellite']),
'new_dxcc_eme' => count($report['new_dxcc_eme']),
'new_gridsquares' => count($report['new_grids']),
'new_gridsquares_hf' => count($report['new_grids_hf']),
'new_gridsquares_satellite' => count($report['new_grids_satellite']),
'new_gridsquares_eme' => count($report['new_grids_eme']),
'unique_callsigns' => $report['unique_callsigns'],
'countries_worked' => count($report['countries_worked'])
),
'details' => array(
'new_countries' => $report['new_dxcc'],
'new_countries_by_band' => $report['new_dxcc_by_band'],
'new_countries_satellite' => $report['new_dxcc_satellite'],
'new_countries_eme' => $report['new_dxcc_eme'],
'new_gridsquares' => $report['new_grids'],
'new_gridsquares_by_band' => $report['new_grids_by_band'],
'new_gridsquares_hf' => $report['new_grids_hf'],
'new_gridsquares_satellite' => $report['new_grids_satellite'],
'new_gridsquares_eme' => $report['new_grids_eme'],
'callsigns_worked' => $report['callsign_list'],
'modes_used' => $report['modes'],
'bands_used' => $report['bands'],
'continents_worked' => $report['continents'],
'satellite_qsos' => $report['satellite_qsos'],
'eme_qsos' => $report['eme_qsos'],
'satellite_breakdown' => $report['satellite_breakdown']
),
'statistics' => array(
'qsos_per_day' => round($report['total_qsos'] / date('t', strtotime("$year-$month-01")), 2),
'most_active_band' => $report['top_band'],
'most_used_mode' => $report['top_mode']
),
'ai_prompt_suggestion' => "Write an engaging amateur radio blog post about my " . $month_name . " " . $year . " operating activity. I made " . $report['total_qsos'] . " contacts" .
(count($report['new_dxcc']) > 0 ? ", worked " . count($report['new_dxcc']) . " new countries" : "") .
(count($report['new_grids']) > 0 ? ", and confirmed " . count($report['new_grids']) . " new gridsquares" : "") .
". Focus on the highlights and make it sound exciting for fellow radio enthusiasts."
);
// Set headers for JSON download
$filename = "monthly_report_{$year}_{$month}.json";
$this->output
->set_content_type('application/json')
->set_header('Content-Disposition: attachment; filename="' . $filename . '"')
->set_output(json_encode($export, JSON_PRETTY_PRINT));
}
/**
* Export report as plain text for AI consumption
*/
public function export_text()
{
$this->load->model('monthlyreport_model');
$this->load->model('logbooks_model');
// Get parameters from POST
$logbook_id = $this->input->post('logbook_id');
$year = $this->input->post('year');
$month = $this->input->post('month');
// Get logbook relationships
$logbooks_locations_array = $this->logbooks_model->list_logbook_relationships($logbook_id);
// Generate report data
$report = $this->monthlyreport_model->generate_report($logbooks_locations_array, $year, $month);
$logbook_name = $this->logbooks_model->find_name($logbook_id);
$month_name = date('F', mktime(0, 0, 0, $month, 1));
// Create plain text report
$text = "AMATEUR RADIO MONTHLY ACTIVITY REPORT\n";
$text .= "========================================\n\n";
$text .= "Logbook: {$logbook_name}\n";
$text .= "Period: {$month_name} {$year}\n";
$text .= "Generated: " . date('Y-m-d H:i:s') . "\n\n";
$text .= "SUMMARY\n";
$text .= "-------\n";
$text .= "Total QSOs: {$report['total_qsos']}\n";
$text .= "Unique Callsigns Worked: {$report['unique_callsigns']}\n";
$text .= "New DXCC Entities: " . count($report['new_dxcc']) . "\n";
$text .= "New Gridsquares: " . count($report['new_grids']) . "\n";
$text .= "Countries Worked: " . count($report['countries_worked']) . "\n\n";
if (count($report['new_dxcc']) > 0) {
$text .= "NEW COUNTRIES THIS MONTH - OVERALL\n";
$text .= "----------------------------------\n";
foreach ($report['new_dxcc'] as $dxcc) {
$text .= "- {$dxcc['name']}\n";
}
$text .= "\n";
}
if (!empty($report['new_dxcc_by_band'])) {
$text .= "NEW COUNTRIES BY BAND\n";
$text .= "---------------------\n";
// Bands already sorted in model
foreach ($report['new_dxcc_by_band'] as $band => $dxcc_list) {
$text .= "\n{$band} (" . count($dxcc_list) . " new):\n";
foreach ($dxcc_list as $dxcc) {
$text .= " - {$dxcc['name']}";
if (!empty($dxcc['callsign'])) {
$text .= " (worked {$dxcc['callsign']}";
if (!empty($dxcc['mode'])) {
$text .= " on {$dxcc['mode']}";
}
$text .= ")";
}
$text .= "\n";
}
}
$text .= "\n";
}
if (count($report['new_dxcc_satellite']) > 0) {
$text .= "NEW COUNTRIES VIA SATELLITE\n";
$text .= "---------------------------\n";
foreach ($report['new_dxcc_satellite'] as $dxcc) {
$text .= "- {$dxcc['name']}";
if (!empty($dxcc['callsign'])) {
$text .= " (worked {$dxcc['callsign']}";
if (!empty($dxcc['mode'])) {
$text .= " on {$dxcc['mode']}";
}
$text .= ")";
}
$text .= "\n";
}
$text .= "\n";
}
if (count($report['new_dxcc_eme']) > 0) {
$text .= "NEW COUNTRIES VIA EME (MOONBOUNCE)\n";
$text .= "----------------------------------\n";
foreach ($report['new_dxcc_eme'] as $dxcc) {
$text .= "- {$dxcc['name']}";
if (!empty($dxcc['callsign'])) {
$text .= " (worked {$dxcc['callsign']}";
if (!empty($dxcc['mode'])) {
$text .= " on {$dxcc['mode']}";
}
$text .= ")";
}
$text .= "\n";
}
$text .= "\n";
}
if (count($report['new_grids']) > 0) {
$text .= "NEW GRIDSQUARES THIS MONTH\n";
$text .= "--------------------------\n";
if (!empty($report['new_grids_by_band'])) {
foreach ($report['new_grids_by_band'] as $band => $grids_list) {
$text .= "\n{$band} (" . count($grids_list) . " new):\n";
foreach ($grids_list as $grid) {
$text .= " {$grid['grid']}";
if (!empty($grid['callsign'])) {
$text .= " ({$grid['callsign']}";
if (!empty($grid['satellite'])) {
$text .= " via {$grid['satellite']}";
}
if (!empty($grid['mode'])) {
$text .= " - {$grid['mode']}";
}
$text .= ")";
}
$text .= "\n";
}
}
}
$text .= "\n";
} $text .= "MODES USED\n";
$text .= "----------\n";
foreach ($report['modes'] as $mode => $count) {
$text .= sprintf("%-10s %d QSOs\n", $mode, $count);
}
$text .= "\n";
$text .= "BANDS USED\n";
$text .= "----------\n";
foreach ($report['bands'] as $band => $count) {
$text .= sprintf("%-10s %d QSOs\n", $band, $count);
}
$text .= "\n";
if (!empty($report['continents'])) {
$text .= "CONTINENTAL DISTRIBUTION\n";
$text .= "------------------------\n";
foreach ($report['continents'] as $continent => $count) {
$text .= sprintf("%-15s %d QSOs\n", $continent, $count);
}
$text .= "\n";
}
if (!empty($report['callsign_list'])) {
$text .= "UNIQUE CALLSIGNS WORKED (" . count($report['callsign_list']) . ")\n";
$text .= "----------------------------\n";
foreach ($report['callsign_list'] as $callsign) {
$text .= sprintf("%-15s %d QSO%s\n", $callsign['callsign'], $callsign['qso_count'], $callsign['qso_count'] > 1 ? 's' : '');
}
$text .= "\n";
}
if ($report['satellite_qsos'] > 0) {
$text .= "SATELLITE ACTIVITY\n";
$text .= "------------------\n";
$text .= "Total Satellite QSOs: {$report['satellite_qsos']}\n";
if (!empty($report['satellite_breakdown'])) {
$text .= "\nQSOs per Satellite:\n";
foreach ($report['satellite_breakdown'] as $sat) {
$text .= sprintf(" %-20s %3d QSOs (%s%%)\n", $sat['satellite'], $sat['qso_count'], $sat['percentage']);
}
}
$text .= "\n";
}
if ($report['eme_qsos'] > 0) {
$text .= "EME (MOONBOUNCE) ACTIVITY\n";
$text .= "-------------------------\n";
$text .= "Total EME QSOs: {$report['eme_qsos']}\n\n";
}
$text .= "STATISTICS\n";
$text .= "----------\n";
$days_in_month = date('t', strtotime("$year-$month-01"));
$text .= "Average QSOs per day: " . round($report['total_qsos'] / $days_in_month, 2) . "\n";
$text .= "Most active band: {$report['top_band']}\n";
$text .= "Most used mode: {$report['top_mode']}\n\n";
$text .= "---\n";
$text .= "This report can be used to generate an article about your amateur radio activity.\n";
$text .= "Consider using an AI tool like ChatGPT or Claude to create an engaging blog post from this data.\n";
// Set headers for text download
$filename = "monthly_report_{$year}_{$month}.txt";
$this->output
->set_content_type('text/plain')
->set_header('Content-Disposition: attachment; filename="' . $filename . '"')
->set_output($text);
}
}