League of Women Voters of West Virginia

Custom-developed software designed for the League of Women Voters of West Virginia, as well as any state or local League affiliated with the League of Women Voters.

IMPORTANT: Format for roster

NEW (December 2025): MAL are now included in the Local League Membership in Your State. This makes issues with the MALspecific list irrelevant, since it is no longer required.

NEW (July 2025): A new column has been added to the roster for MAL. To resolve this, remove the Middle Name column.

REQUIRED FILE

A file called env is required in the same directory as the programs. This file contains configuration for both the Perl and JavaScript scripts.

Complete env File Example

# Portal Configuration (for download-roster.js and save-session.js)
$PORTAL_URL = "https://portal.lwv.org";
$MEMBERSHIP_URL = "https://portal.lwv.org/groups/43a93df1-901a-4676-88c3-f4ea430d4884/league_membership_state_view";

# Email Notification Settings (for download-roster.js - error notifications via s-nail)
$SMTP_HOST = "mail.bikelover.org";
$SMTP_PORT = "587";
$SMTP_USE_STARTTLS = "true";
$SMTP_AUTH = "login";
$SMTP_USER = "your-email@lwv.org";
$SMTP_PASSWORD = "your-password";
$SSL_VERIFY_IGNORE = "ignore";
$EMAIL_FROM = "your-email@lwv.org";
$EMAIL_TO = "recipient@lwv.org";

# Google API Configuration (for google-civic-api.pl)
$key = "your-google-api-key";
$STATE = "WV";
$stateLeagueID = "WV000";
$localLeagueIDs = "WV102|WV103|WV112";

Configuration Details

Variable Required Description
PORTAL_URL Yes Base URL of the LWV portal (default: https://portal.lwv.org)
MEMBERSHIP_URL Yes Your league's membership page URL. Find this by navigating to your league's membership page in the portal and copying the URL
SMTP_HOST No SMTP server hostname for error email notifications (requires s-nail)
SMTP_PORT No SMTP server port (default: 587)
SMTP_USE_STARTTLS No Enable STARTTLS for SMTP (default: true)
SMTP_AUTH No SMTP auth type (default: login)
SMTP_USER No SMTP authentication username
SMTP_PASSWORD No SMTP authentication password
SSL_VERIFY_IGNORE No SSL verify setting for SMTP (default: ignore)
EMAIL_FROM No Sender email address for error notifications
EMAIL_TO No Recipient email address for error notifications
key Optional Google Civic Information API key. See Google API credentials - restrict key to the Google Civic Information API. Required for google-civic-api.pl.
STATE Required* Two-letter state code (e.g., WV). Required for google-civic-api.pl.
stateLeagueID Required* State league ID (e.g., WV000). Required for google-civic-api.pl.
localLeagueIDs Required* Pipe-separated list of local league IDs. Required for google-civic-api.pl.

*Required for google-civic-api.pl

JavaScript Scripts (download-roster.js and save-session.js)

These scripts automate downloading the membership roster CSV from the LWV portal.

Prerequisites

# Install Node.js dependencies
npm install playwright
npx playwright install chromium

# Install s-nail (required for error email notifications)
# On Debian/Ubuntu:
sudo apt-get install s-nail

First-Time Setup (Run Once)

Before running the download script for the first time, you need to save your browser session:

node save-session.js

This will:

  1. Open a browser window
  2. Prompt you to log in using the magic link method (email)
  3. Wait for you to complete login and press Enter
  4. Save your session to .session.json

The session is valid for 10 years (indefinite), but if it ever expires or fails, running save-session.js again will refresh it.

Downloading the Roster

To download the latest membership CSV:

node download-roster.js

This will:

  1. Load your saved session
  2. Navigate to the membership page
  3. Click Export → Download
  4. Save the CSV file with timestamp (e.g., league_membership_state_view_2026-04-15T05-00-24.csv)

Testing Error Email

To test that error emails work correctly:

# Temporarily rename the session file
mv .session.json .session.json.bak

# Run download - should fail and send error email
node download-roster.js

# Restore the session file
mv .session.json.bak .session.json

Error Notifications

When download-roster.js fails (due to missing/expired session, download error, etc.), it will send an error email via s-nail to the address specified in EMAIL_TO. The email will include:

  • The error message
  • Instructions to run save-session.js to refresh the session

Note: s-nail must be installed for error emails to work. See Prerequisites above.

LLAW Google Civic Information API Query version 2

Copyright (C) 2025 - by Jonathan Rosenbaum

This may be freely redistributed under the terms of the GNU General Public License

Usage:  ./google-civic-api.pl google ./roster-file  (queries Google Civic Api Delegate and Senate District for all LWVWV members)
    ./google-civic-api.pl WV000 '*.csv' (show all information for members at large, but do not query Google)
    ./google-civic-api.pl WV000 '*.csv' email (only show email addresses for members at large, but do not query Google)

1st argument can be one of these types:
    google (all members with senate/delegate district query) which prints out this csv data:
        'Name,Email,Phone,Address,Delegate District,Senate District,League ID,Join Date'
    ALL (all members without senate/delegate district query)
    League ID:  WV000 (members at large)  WV102 (Huntington) WV103 (Morgantown-Monogalia)  WV112 (Jefferson)

2nd argument must be the location of the LWVWV roster file, and prints out this csv information:
    Name,Email,Phone,Address,Join Date,

3rd argument 'email' will only print out the email addresses, and only works with the ALL or League ID type argument

You will want to send results to a file.
    Example:  ./google-civic-api.pl google '*.csv' > 2023-districts
Description
Custom-developed software designed for the League of Women Voters of West Virginia, as well as any state or local League affiliated with the League of Women Voters.
Readme GPL-3.0 90 KiB
Languages
Perl 51.5%
JavaScript 48.5%