Removes positional dependency for csv header
This commit is contained in:
parent
404f0cd56f
commit
1dca98898e
@ -3,24 +3,16 @@ use warnings;
|
||||
use strict;
|
||||
|
||||
# PORTAL CHANGES - assumes you have roster permission for the State League group
|
||||
# Since the portal came online, you now need to process two different types of cvs files: One for all local Leagues (Local Leagues) & one for the MALs (Roster)
|
||||
# * * * * * * * * * *
|
||||
# LEAGUE - First Name Preferred First Name Last Name Email Phone Mailing Street Mailing City Mailing State Mailing Postal Code Mailing Country League Name League ID Status Original Join Date Expiration Date Unique Contact Id Unique Account Id
|
||||
# (diff) (diff)
|
||||
# MAL - First Name Preferred First Name Last Name Phone Email Mailing Street Mailing City Mailing State Mailing Postal Code Mailing Country Original Join Date Expiration Date Last Login Date Unique Contact Id Unique Account Id
|
||||
|
||||
# Required local Leagues MAL
|
||||
# Preferred First Name [1] [1]
|
||||
# Last Name [2] [2]
|
||||
# Email [3] [4]
|
||||
# Phone [4] [3]
|
||||
# Mailing Street [5] [5]
|
||||
# Mailing City [6] [6]
|
||||
# Mailing State [7] [7]
|
||||
# Mailing Postal Code [8] [8]
|
||||
# League ID [11] Assumed
|
||||
# Status [12] not used not used
|
||||
# Original Join Date [13] [10]
|
||||
# Since the portal came online, CSV columns are accessed by name rather than position
|
||||
# to handle column reordering. The script parses the header row to create a mapping.
|
||||
#
|
||||
# Required columns (must exist in CSV):
|
||||
# First Name, Last Name, Email, Phone, Mailing Street, Mailing City,
|
||||
# Mailing State, Mailing Postal Code, Status
|
||||
#
|
||||
# Optional columns:
|
||||
# League ID (if missing, assumes Members At Large)
|
||||
# Joined or Original Join Date (for join date)
|
||||
|
||||
# Google Civic Information API
|
||||
# Quota: Queries per minute
|
||||
@ -82,30 +74,57 @@ if ( $ARGV[2] ) {
|
||||
}
|
||||
}
|
||||
|
||||
# Open roster file .. hopefully columns remain the same,
|
||||
# but @fields can be adjusted as required.
|
||||
# Open roster file
|
||||
foreach my $file (@files) {
|
||||
|
||||
#
|
||||
# $file = $ARGV[1];
|
||||
my $fh;
|
||||
$| = 1;
|
||||
open $fh, "<", $file;
|
||||
open $fh, "<", $file or die "Cannot open $file: $!";
|
||||
|
||||
my $curl = WWW::Curl::Simple->new();
|
||||
|
||||
# Read the first line
|
||||
my $localLeague;
|
||||
# Read and parse the header line to create column mapping
|
||||
my $header = <$fh>;
|
||||
print "Header: $header" unless $emailCsvArg; # Output the header for reference
|
||||
# Decide how to process
|
||||
if ( $header !~ /League ID/ ) {
|
||||
print "Processing file: $file ... No League ID found, must be MAL\n" unless $emailCsvArg;
|
||||
$localLeague = 0; # This is a Members At Large (MAL) file
|
||||
chomp $header;
|
||||
print "Header: $header\n" unless $emailCsvArg;
|
||||
|
||||
# Parse header to get column indices by name
|
||||
my @headers = parse_csv_line($header);
|
||||
my %col; # Column name -> index mapping
|
||||
for (my $i = 0; $i < @headers; $i++) {
|
||||
my $h = $headers[$i];
|
||||
$h =~ s/^"//;
|
||||
$h =~ s/"$//;
|
||||
$h =~ s/^\s+|\s+$//g; # Trim whitespace
|
||||
$col{$h} = $i;
|
||||
}
|
||||
|
||||
# Verify required columns exist
|
||||
my @required_cols = ('First Name', 'Last Name', 'Email', 'Phone', 'Mailing Street',
|
||||
'Mailing City', 'Mailing State', 'Mailing Postal Code', 'Status');
|
||||
my @missing;
|
||||
foreach my $col_name (@required_cols) {
|
||||
unless (exists $col{$col_name}) {
|
||||
push @missing, $col_name;
|
||||
}
|
||||
}
|
||||
if (@missing) {
|
||||
warn "ERROR: Required columns not found in $file:\n";
|
||||
warn " Missing: " . join(", ", @missing) . "\n";
|
||||
warn " Available columns: " . join(", ", @headers) . "\n";
|
||||
close $fh;
|
||||
next; # Skip this file
|
||||
}
|
||||
|
||||
# Determine file type based on League ID column presence
|
||||
my $localLeague;
|
||||
if (exists $col{'League ID'}) {
|
||||
print "Processing file: $file ... League ID column found\n" unless $emailCsvArg;
|
||||
$localLeague = 1;
|
||||
}
|
||||
else {
|
||||
print "Processing file: $file ... League ID found\n" unless $emailCsvArg;
|
||||
$localLeague = 1; # This is local League file
|
||||
print "Processing file: $file ... No League ID column, must be MAL\n" unless $emailCsvArg;
|
||||
$localLeague = 0;
|
||||
}
|
||||
|
||||
my $csv =
|
||||
@ -115,41 +134,52 @@ foreach my $file (@files) {
|
||||
|
||||
while ( my $line = <$fh> ) {
|
||||
|
||||
# my @fields = split( /,/, $line );
|
||||
# may be commas between those quotes
|
||||
# pulled this regexp from https://stackoverflow.com/questions/18144431/regex-to-split-a-csv (solution 45)
|
||||
my @fields =
|
||||
$line =~ m/(?:,|\n|^)("(?:(?:"")*[^"]*)*"|[^",\n]*|(?:\n|$))/g
|
||||
; #m/("[^"]+"|[^,]+)(?:,\s*)?/g;
|
||||
# print $#fields . "\n";
|
||||
my $leagueId, my $phone, my $email, my $joinDate, my $status;
|
||||
my @fields = parse_csv_line($line);
|
||||
|
||||
# Helper to get field value by column name
|
||||
my $get_field = sub {
|
||||
my ($name) = @_;
|
||||
my $idx = $col{$name};
|
||||
unless (defined $idx) {
|
||||
warn "ERROR: Column '$name' not found in file $file\n";
|
||||
warn "Available columns: " . join(", ", keys %col) . "\n";
|
||||
return undef;
|
||||
}
|
||||
my $val = $fields[$idx];
|
||||
$val =~ s/^"//;
|
||||
$val =~ s/"$//;
|
||||
return $val;
|
||||
};
|
||||
|
||||
my ($leagueId, $phone, $email, $joinDate, $status);
|
||||
|
||||
if ($localLeague) {
|
||||
|
||||
# Local League file processing
|
||||
# Updated for new CSV header format (as of 2026-05-02)
|
||||
# First Name[0],Preferred First Name[1],League Name[2],League ID[3],Status[4],Joined[5],Expiration[6],Unique Contact Id[7],Unique Account Id[8],Last Name[9],Email[10],Phone[11],Mailing Street[12],Mailing City[13],Mailing State[14],Mailing Postal Code[15],Mailing Country[16]
|
||||
( $leagueId = $fields[3] ) =~ s/"//g; # League ID [was 11]
|
||||
( $phone = $fields[11] ) =~ s/"//g; # Phone [was 4]
|
||||
( $email = $fields[10] ) =~ s/"//g; # Email [was 3]
|
||||
( $joinDate = $fields[5] ) =~ s/"//g; # Join Date [was 13]
|
||||
( $status = $fields[4] ) =~ s/"//g; # Status [was 12]
|
||||
$leagueId = $get_field->('League ID');
|
||||
$phone = $get_field->('Phone');
|
||||
$email = $get_field->('Email');
|
||||
$joinDate = $get_field->('Joined');
|
||||
$status = $get_field->('Status');
|
||||
}
|
||||
else {
|
||||
# Members At Large (MAL) file processing
|
||||
# Updated for new CSV header format (as of 2026-05-02)
|
||||
# League ID is assumed to be WV000 for all MALs
|
||||
$leagueId = $stateLeagueID; # Default for MALs
|
||||
( $phone = $fields[11] ) =~ s/"//g; # Phone [was 3]
|
||||
( $email = $fields[10] ) =~ s/"//g; # Email [was 4]
|
||||
( $joinDate = $fields[5] ) =~ s/"//g; # Join Date [was 10]
|
||||
( $status = $fields[4] ) =~ s/"//g; # Status [was 13]
|
||||
$leagueId = $stateLeagueID; # Default for MALs
|
||||
$phone = $get_field->('Phone');
|
||||
$email = $get_field->('Email');
|
||||
$joinDate = $get_field->('Original Join Date');
|
||||
$status = $get_field->('Status');
|
||||
}
|
||||
|
||||
my $firstName = $get_field->('First Name');
|
||||
my $lastName = $get_field->('Last Name');
|
||||
my $street = $get_field->('Mailing Street');
|
||||
my $city = $get_field->('Mailing City');
|
||||
my $state = $get_field->('Mailing State');
|
||||
my $zip = $get_field->('Mailing Postal Code');
|
||||
|
||||
# Check for undefined values (missing columns)
|
||||
unless (defined $firstName && defined $lastName) {
|
||||
warn "ERROR: Missing required First Name or Last Name in record, skipping\n";
|
||||
next;
|
||||
}
|
||||
( my $firstName = $fields[0] ) =~ s/"//g; # First Name [unchanged]
|
||||
( my $lastName = $fields[9] ) =~ s/"//g; # Last Name [was 2]
|
||||
( my $street = $fields[12] ) =~ s/"//g; # Street [was 5]
|
||||
( my $city = $fields[13] ) =~ s/"//g; # City [was 6]
|
||||
( my $state = $fields[14] ) =~ s/"//g; # State [was 7]
|
||||
( my $zip = $fields[15] ) =~ s/"//g; # Zip [was 8]
|
||||
next if $street eq "Mailing Street";
|
||||
|
||||
# Filter for Primary status only (Primary, Primary - Life, etc.)
|
||||
@ -304,6 +334,21 @@ foreach my $file (@files) {
|
||||
|
||||
}
|
||||
|
||||
# Helper function to parse a CSV line into fields
|
||||
# Handles quoted fields and commas within quotes
|
||||
sub parse_csv_line {
|
||||
my ($line) = @_;
|
||||
chomp $line;
|
||||
|
||||
# Use the same regex pattern that was already in the code
|
||||
my @fields = $line =~ m/(?:,|\n|^)("(?:(?:"")*[^"]*)*"|[^",\n]*|(?:\n|$))/g;
|
||||
|
||||
# Remove the extra empty field that the regex sometimes captures at the end
|
||||
pop @fields while @fields && $fields[-1] eq '';
|
||||
|
||||
return @fields;
|
||||
}
|
||||
|
||||
# skip over invalid and nonexistent email addresses
|
||||
sub email {
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user