Fixing bugs in 'make_email'

Community_News/make_email: Many bugs relating to the review month versus
    the recording date. Some of these must have been there for 12 years!
    Rerwrote several parts and added a function for converting Perl date
    formats. Added '-force' option to turn off checks when the script is
    run in the month after a review month (not uncommon, but fairly
    infrequent). Fix for writing bad records to the date cache file.
    Updates to POD documentation.

Community_News/make_email_template.tpl: Added new shared variables for
    the review year and month as opposed to the recording year and
    month. Improved the text explaining the "handouts" versus the final
    show notes. Removed the reference to the target show itself. This
    used to be where the "handout" notes were written, then they were
    replaced before show release. This isn't being done any more.

Community_News/recording_dates.dat: Updated with the correct recording
    date (and time) for the review of shows in March 2025.
This commit is contained in:
Dave Morriss 2025-04-03 16:57:57 +01:00
parent 2000398ad8
commit b6c1a5b766
3 changed files with 144 additions and 60 deletions

View File

@ -5,7 +5,7 @@
# #
# USAGE: ./make_email [-debug=N] [-month=DATE] [-date=DATE] # USAGE: ./make_email [-debug=N] [-month=DATE] [-date=DATE]
# [-start=START_TIME] [-end=END_TIME] [-output[=FILE]] # [-start=START_TIME] [-end=END_TIME] [-output[=FILE]]
# [-config=FILE] # [-[no]force] [-config=FILE]
# #
# DESCRIPTION: Make an invitation email for the next Community News # DESCRIPTION: Make an invitation email for the next Community News
# with times per timezone. # with times per timezone.
@ -37,7 +37,7 @@
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com # AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
# VERSION: 0.3.3 # VERSION: 0.3.3
# CREATED: 2013-10-28 20:35:22 # CREATED: 2013-10-28 20:35:22
# REVISION: 2025-02-28 14:40:28 # REVISION: 2025-04-03 14:42:45
# #
#=============================================================================== #===============================================================================
@ -537,6 +537,7 @@ my $date = $options{date};
my $start = $options{starttime}; my $start = $options{starttime};
my $end = $options{endtime}; my $end = $options{endtime};
my $outfile = $options{output}; my $outfile = $options{output};
my $force = ( defined( $options{force} ) ? $options{force} : 0 );
my $cfgfile my $cfgfile
= ( defined( $options{config} ) ? $options{config} : $configfile ); = ( defined( $options{config} ) ? $options{config} : $configfile );
@ -666,7 +667,7 @@ $dbh->{sqlite_unicode} = 1;
my @today = Today(); my @today = Today();
my @startdate; my @startdate;
my @startmonth; my @startmonth;
my @reviewdate; #my @reviewdate;
my $monday = 1; # Day of week number 1-7, Monday-Sunday my $monday = 1; # Day of week number 1-7, Monday-Sunday
my $offset = day_offset($dayname)->{offset}; my $offset = day_offset($dayname)->{offset};
@ -692,7 +693,7 @@ if ( defined($date) ) {
$parsed[4] += 1; $parsed[4] += 1;
@startdate = @parsed[ 5, 4, 3 ]; @startdate = @parsed[ 5, 4, 3 ];
die "Date is in the past '$date'; aborting\n" die "Date is in the past '$date'; aborting\n"
unless ( Date_to_Days(@startdate) > Date_to_Days(@today) ); unless ( $force || Date_to_Days(@startdate) > Date_to_Days(@today) );
} }
elsif ( defined($month) ) { elsif ( defined($month) ) {
# #
@ -708,7 +709,7 @@ elsif ( defined($month) ) {
$parsed[4] += 1; $parsed[4] += 1;
@startmonth = @parsed[ 5, 4, 3 ]; @startmonth = @parsed[ 5, 4, 3 ];
die "Date is in the past '$month'; aborting\n" die "Date is in the past '$month'; aborting\n"
unless ( Date_to_Days(@startmonth) > Date_to_Days(@today) ); unless ( $force || Date_to_Days(@startmonth) > Date_to_Days(@today) );
# #
# Compute the next meeting date from now (by finding the next first Monday # Compute the next meeting date from now (by finding the next first Monday
@ -731,28 +732,25 @@ _debug($DEBUG >= 2, '@startdate: ' . join(',',@startdate));
# The month being reviewed is sometimes the same month and sometimes the month # The month being reviewed is sometimes the same month and sometimes the month
# before. # before.
# #
if ( $startdate[1] eq $today[1] ) { #if ( $startdate[1] eq $today[1] ) {
# Same month # # Same month
@reviewdate = @startdate; # @reviewdate = @startdate;
} #}
else { #else {
# Previous month - backup 1 month # # Previous month - backup 1 month
@reviewdate = Add_Delta_YM( @startdate, 0, -1 ); # @reviewdate = Add_Delta_YM( @startdate, 0, -1 );
} #}
#
_debug($DEBUG >= 2, '@reviewdate: ' . join(',',@reviewdate)); #_debug($DEBUG >= 2, '@reviewdate: ' . join(',',@reviewdate));
# #
# Transfer Date::Calc values into hashes for initialising DateTime objects so # Transfer Date::Calc values into DateTime objects so
# we can play time zone games. (Note: %dtargs is a hash and we're using hash # we can get better formatting.
# slicing to initialise it).
# #
my ( %dtargs, $dtstart, $dtend ); my ( $dtrevmonth, $dtstart, $dtend );
@dtargs{ 'year', 'month', 'day', 'hour', 'minute', 'second', 'time_zone' } $dtrevmonth = dc_to_dt( \@startmonth );
= ( @startdate, @starttime, 'UTC' ); $dtstart = dc_to_dt( [ @startdate, @starttime ] );
$dtstart = DateTime->new(%dtargs); $dtend = dc_to_dt( [ @startdate, @endtime ] );
@dtargs{ 'hour', 'minute', 'second' } = (@endtime);
$dtend = DateTime->new(%dtargs);
# #
# Compute the number of days until the recording # Compute the number of days until the recording
@ -763,15 +761,31 @@ my $dtf = DateTime::Format::Duration->new( pattern => '%e' );
my $days = $dtf->format_duration($dtoffset); my $days = $dtf->format_duration($dtoffset);
# #
# Formatted dates for the mail message body # Formatted datetime-related values for the mail message body
# #
my ( $year, $monthno, $monthname, $nicedate, $starttime, $endtime ) = ( my ( $revyear, $revmonthno, $revmonthname ) = (
$dtstart->strftime("%Y"), $dtstart->strftime("%m"), $dtrevmonth->year,
Month_to_Text( $reviewdate[1] ), $dtstart->strftime("%A, %B %d %Y"), $dtrevmonth->month,
$dtstart->strftime("%R (%Z)"), $dtend->strftime("%R (%Z)"), $dtrevmonth->month_name
);
my ( $year, $monthno, $monthname ) = (
$dtstart->year,
$dtstart->month,
$dtstart->month_name
);
my ( $nicedate, $starttime, $endtime ) = (
$dtstart->strftime("%A, %B %d %Y"),
$dtstart->strftime("%R (%Z)"),
$dtend->strftime("%R (%Z)"),
); );
_debug($DEBUG >= 2, _debug($DEBUG >= 2,
"----",
"\$revyear: $revyear",
"\$revmonthno: $revmonthno",
"\$revmonthname: $revmonthname",
"\$year: $year", "\$year: $year",
"\$monthno: $monthno", "\$monthno: $monthno",
"\$monthname: $monthname", "\$monthname: $monthname",
@ -781,7 +795,7 @@ _debug($DEBUG >= 2,
); );
# #
# Build the subject line # Build the subject line (with the recording date)
# #
my $waittime = ( $days > 6 ? "in $days days" : "next %A" ); my $waittime = ( $days > 6 ? "in $days days" : "next %A" );
my $next = ( $days > 6 ? '' : 'next ' ); my $next = ( $days > 6 ? '' : 'next ' );
@ -797,7 +811,7 @@ _debug( $DEBUG >= 2, "\$subject: $subject" );
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
my $outfh; my $outfh;
if ($outfile) { if ($outfile) {
$outfile = sprintf( $outfile, sprintf( "%d-%02d", $year, $monthno ) ) $outfile = sprintf( $outfile, sprintf( "%d-%02d", $revyear, $revmonthno ) )
if ( $outfile =~ /%s/ ); if ( $outfile =~ /%s/ );
open( $outfh, ">:encoding(UTF-8)", $outfile ) open( $outfh, ">:encoding(UTF-8)", $outfile )
@ -861,7 +875,7 @@ $dbh->disconnect;
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# Update the date cache now we have the date and time details we need. # Update the date cache now we have the date and time details we need.
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
( my $monthkey = $dtstart->ymd ) =~ s/\d+$/01/; ( my $monthkey = $dtrevmonth->ymd ) =~ s/\d+$/01/;
my $datestamp = $dtstart->strftime("%F %T"); my $datestamp = $dtstart->strftime("%F %T");
if (exists($recdates{$monthkey})) { if (exists($recdates{$monthkey})) {
@ -899,14 +913,16 @@ my $vars = {
subject => $subject, subject => $subject,
timezones => \@timezones, timezones => \@timezones,
utc => { utc => {
days => $days, days => $days,
month => $monthname, revmonth => $revmonthname,
year => $year, revyear => $revyear,
date => $nicedate, month => $monthname,
start => $starttime, year => $year,
end => $endtime, date => $nicedate,
start => $starttime,
end => $endtime,
}, },
episode => $episode, # show number episode => $episode, # show number
}; };
my $document; my $document;
@ -1009,7 +1025,7 @@ sub append_cache {
# positions for writing (using 'seek'). The now empty file is # positions for writing (using 'seek'). The now empty file is
# filled with data from the hash and closed. # filled with data from the hash and closed.
# THROWS: No exceptions # THROWS: No exceptions
# COMMENTS: None # COMMENTS: Uses 'copy' from File::Copy
# SEE ALSO: N/A # SEE ALSO: N/A
#=============================================================================== #===============================================================================
sub update_cache { sub update_cache {
@ -1107,6 +1123,56 @@ sub validate_time {
return $time; return $time;
} }
#=== FUNCTION ================================================================
# NAME: dc_to_dt
# PURPOSE: Converts a Date::Calc datetime into a DateTime equivalent
# PARAMETERS: $refdt Reference to an array holding a Date::Calc
# date and time
# RETURNS: Returns a DateTime object converted from the input
# DESCRIPTION: Takes an arrayref which is expected to have a Date::Calc date
# and time. If the referenced array is too short it has three
# zero elements added to it and is checked again, aborting if
# it's still the wrong length.
# THROWS: No exceptions
# COMMENTS: None
# SEE ALSO: N/A
#===============================================================================
sub dc_to_dt {
my ($refdt) = @_;
#
# Copy the incoming arrayref into an array to avoid writing data back
#
my @dt = @$refdt;
#
# Check we got a 6-element array and add a default time if not
#
if (scalar(@dt) < 6) {
push(@dt,0,0,0);
}
#
# Should be 6 elements now
#
die "Invalid Date::Calc date and time (@dt) in dc_to_dt\n"
unless (scalar(@dt) == 6);
#
# Convert to DateTime to get access to formatting stuff, default to UTC.
# (Note: %dtargs is a hash and we're using hash slicing to initialise it).
#
my ( %dtargs, $dt );
@dtargs{ 'year', 'month', 'day', 'hour', 'minute', 'second', 'time_zone' }
= ( @dt, 'UTC' );
$dt = DateTime->new(%dtargs);
#
# Return the date and time as a DateTime object
#
return $dt;
}
#=== FUNCTION ================================================================ #=== FUNCTION ================================================================
# NAME: make_date # NAME: make_date
# PURPOSE: Make the event date for recurrence # PURPOSE: Make the event date for recurrence
@ -1331,7 +1397,7 @@ sub Options {
"debug=i", "date=s", "debug=i", "date=s",
"starttime=s", "endtime=s", "starttime=s", "endtime=s",
"month=s", "output:s", "month=s", "output:s",
"config=s", "config=s", "force!",
); );
# "mail!", "fromaddress=s", "toaddress=s", "duration=s", # "mail!", "fromaddress=s", "toaddress=s", "duration=s",
@ -1362,9 +1428,19 @@ This documentation refers to make_email version 0.3.3
=head1 USAGE =head1 USAGE
make_email [-help] [-documentation] [-debug=N] [-month=DATE] [-date=DATE] make_email [-help] [-documentation] [-debug=N] [-month=DATE] [-date=DATE]
[-start=START_TIME] [-end=END_TIME] [-config=FILE] [-start=START_TIME] [-end=END_TIME] [-[no]force] [-config=FILE]
./make_email -date=2022-12-27 1. ./make_email -date=2022-12-27
Generate email for a specific date (in the future)
2. ./make_email -force -month=2025-03-01 -start=16:00 -out=HPR_email_%s.txt
Assume this is run in early April 2025. Normally, generating email for
March would not be allowed since it's in the past, so -force is needed
to override the checks. The start day is the default Friday, and the
start time is set to 16:00. The message (email body) is written to
HPR_email_2025-03.txt. The date cache (recording_dates.dat) will be
updated with the line:
2025-03-01,2025-04-04 16:00:00
=head1 OPTIONS =head1 OPTIONS
@ -1474,9 +1550,9 @@ This option defines an output file to receive the mail message text. If the opti
omitted the notes are written to STDOUT, allowing them to be redirected if omitted the notes are written to STDOUT, allowing them to be redirected if
required. required.
The output file name may contain the characters 'B<%s>'. This denotes the point The output file name may contain the characters 'B<%s>'. This denotes the
at which the year and month in the format B<YYYY-MM> are inserted. For example point at which the year and the review month in the format B<YYYY-MM> are
if the script is being run for February 2025 the option: inserted. For example if the script is being run for February 2025 the option:
-out=HPR_email_%s.txt -out=HPR_email_%s.txt
@ -1484,6 +1560,14 @@ will cause the generation of the file:
HPR_email_2025-02.txt HPR_email_2025-02.txt
=item B<-[no]force>
Sometimes the recording of the Community News episode for a month takes place
on the first Friday of the next month. If an attempt is made to run this
script to make the email for such a recording in the month after the review
month, safety checks will prevent it. This option, which is normally off, will
allow the script to run and generate the mail message.
=item B<-config=FILE> =item B<-config=FILE>
This option defines a configuration file other than the default This option defines a configuration file other than the default

View File

@ -1,11 +1,11 @@
[%# make_email_template.tpl 2025-02-23 -%] [%# make_email_template.tpl 2025-04-03 -%]
[%# Community News email template -%] [%# Community News email template -%]
[% USE wrap -%] [% USE wrap -%]
[% subject %] [% subject %]
[% FILTER replace('\n', ' ') -%] [% FILTER replace('\n', ' ') -%]
[% IF utc.days > 6 -%] [% IF utc.days > 6 -%]
The Community News for [% utc.month %] will be recorded using Mumble on The Community News for [% utc.revmonth %] will be recorded using Mumble on
[% ELSE -%] [% ELSE -%]
The next Community News will be recorded using Mumble on The next Community News will be recorded using Mumble on
[% END -%] [% END -%]
@ -14,13 +14,13 @@ The next Community News will be recorded using Mumble on
[% FILTER replace('\n', ' ') -%] [% FILTER replace('\n', ' ') -%]
During the recording HPR Volunteers will review the shows released during During the recording HPR Volunteers will review the shows released during
[% utc.month %] [% utc.year %], they will read comments submitted during that [% utc.revmonth %] [% utc.revyear %], they will read comments submitted during that
month, as well as summarising email sent to the HPR mailing list. month, as well as summarising email sent to the HPR mailing list.
[% END %] [% END %]
[% FILTER replace('\n', ' ') -%] [% FILTER replace('\n', ' ') -%]
All HPR listeners are welcome to join in, but we ask that you listen to all All HPR listeners are welcome to join in, but we ask that you listen to all
the shows in [% utc.month %] before you do so. the shows in [% utc.revmonth %] before you do so.
[% END %] [% END %]
[% FILTER replace('\n', ' ') -%] [% FILTER replace('\n', ' ') -%]
@ -32,18 +32,18 @@ make a change.
[% END %] [% END %]
[% FILTER replace('\n', ' ') -%] [% FILTER replace('\n', ' ') -%]
The notes for the recording are an extended version of the show notes. These The notes for the recording are an extended version of the show notes.
extended elements are removed before the show is made fully available on the A version without these extended elements is made for release on the HPR site
HPR site (and on archive.org). Comments which might have been missed in the (and on archive.org). Comments which might have been missed in the last
last recording will be marked in red. Comments which would normally be in this recording will be marked in red in the extended version. Comments which would
month, but which were read out in the last show are marked in green. Comments normally be in this month, but which were read out in the last show are marked
made in the past month to older shows will be displayed in full (so they are in green. Comments made in the past month to older shows will be displayed in
easier to read). full (so they are easier to read).
[% END %] [% END %]
[% FILTER replace('\n', ' ') -%] [% FILTER replace('\n', ' ') -%]
Look here for the notes for this recording: The notes for this recording will be made available to participants before the
https://hackerpublicradio.org/eps/hpr[% episode %]/index.html recording begins.
[% END %] [% END %]
Summary: Summary:

View File

@ -30,4 +30,4 @@
2024-12-01,2025-01-03 15:00:00 2024-12-01,2025-01-03 15:00:00
2025-01-01,2025-01-31 15:00:00 2025-01-01,2025-01-31 15:00:00
2025-02-01,2025-02-28 16:00:00 2025-02-01,2025-02-28 16:00:00
2025-03-01,2025-04-04 15:00:00 2025-03-01,2025-04-04 16:00:00