Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
45f35f8
Adding notif email generation and sending to the iapi
jacob6838 Jan 6, 2026
c8cbeeb
Adding notification email examples
jacob6838 Jan 6, 2026
3d068d4
Adding iapi email controller
jacob6838 Jan 6, 2026
169105e
Fixing EmailServiceTest
jacob6838 Jan 9, 2026
6987b60
Update EmailController.java
jacob6838 Jan 9, 2026
4d4fce5
Update EmailServiceTest.java
jacob6838 Jan 9, 2026
1cb6ae9
Fixing broken config property refs
jacob6838 Jan 9, 2026
8361e8e
Updating email generator comments, colors, and content
jacob6838 Jan 14, 2026
d4deef4
Updating default iapi env vars to avoid localhost
jacob6838 Jan 14, 2026
b5411d8
Update EmailRecipient.java
jacob6838 Jan 14, 2026
9eebbe7
Adding email frequency to tables and queries
jacob6838 Jan 14, 2026
4b79219
Update launch.json
jacob6838 Jan 14, 2026
648b367
Improving getCombinedResponseEntity to handle partial failures
jacob6838 Jan 14, 2026
f748fb6
Removing secure env vars from application.yaml
jacob6838 Jan 15, 2026
06338b1
Renaming email template to email_template.html
jacob6838 Jan 15, 2026
9c89f37
Removing duplicate dependency
jacob6838 Jan 15, 2026
c7676b9
Update services/intersection-api/api/src/main/java/us/dot/its/jpo/ode…
jacob6838 Jan 15, 2026
0a3330b
Handling unsubscribe URL generation errors
jacob6838 Jan 15, 2026
84c8cbe
Merge branch 'intersection-api-email-generation-1' of https://github.…
jacob6838 Jan 15, 2026
f1e79bc
Removing unused methods
jacob6838 Jan 15, 2026
f00d7f2
Cleaning up email generation code
jacob6838 Jan 15, 2026
6825d8d
Writing email provider tests
jacob6838 Jan 15, 2026
791aa48
Merge branch 'develop' into intersection-api-email-generation-1
jacob6838 Jan 19, 2026
6462be9
Adding sql update script
jacob6838 Jan 19, 2026
4c75d2a
Update email_subscription_type_update.sql
jacob6838 Jan 19, 2026
249252e
Merge branch 'develop' into intersection-api-email-generation-1
jacob6838 Jan 22, 2026
7f116b1
SUpporting authenticated SMTP server
jacob6838 Jan 22, 2026
46f3a6d
Merge remote-tracking branch 'origin/develop' into intersection-api-e…
jacob6838 Feb 2, 2026
0ec11f6
Regenerating email postgres JPA objects
jacob6838 Feb 2, 2026
464672c
Working email sending with JPA repositories
jacob6838 Feb 2, 2026
ee3416a
Merge remote-tracking branch 'origin/develop' into intersection-api-e…
jacob6838 Feb 9, 2026
17151f1
Temporarily force enabling emailer
jacob6838 Feb 10, 2026
8c256e5
Renaming INTERSECTION_SMTP_SERVER_HOST
jacob6838 Feb 10, 2026
a3123dd
Merge remote-tracking branch 'origin/develop' into intersection-api-e…
jacob6838 Feb 11, 2026
1ee79f1
Adding spring mail ssl trust policy
jacob6838 Feb 11, 2026
22fc718
Hardcoding gmail for testing
jacob6838 Feb 13, 2026
7a42278
Adding logging for email recipients
jacob6838 Feb 13, 2026
0c6f314
Adding additional iapi email logging
jacob6838 Feb 17, 2026
963b20e
Adding transport listener for email send debugging
jacob6838 Feb 17, 2026
7e19d46
Merge branch 'develop' into intersection-api-email-generation-1
jacob6838 Feb 17, 2026
da2e4bb
Merge branch 'develop' into intersection-api-email-generation-1
jacob6838 Mar 10, 2026
cb54e2c
Adding sentDate header
jacob6838 Mar 10, 2026
c807fae
Reverting add transport listener
jacob6838 Mar 10, 2026
8073ea1
Reverting email logging changes
jacob6838 Mar 10, 2026
b2ee5c5
Combining GlobalExceptionHandlers
jacob6838 Mar 10, 2026
037c27c
Update EmailService.java
jacob6838 Mar 11, 2026
0cb6d11
Merge branch 'develop' into intersection-api-email-generation-1
jacob6838 Mar 13, 2026
71d735b
Merge branch 'develop' into intersection-api-email-generation-1
jacob6838 Mar 17, 2026
d50e16d
Update launch.json
jacob6838 Mar 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,21 @@
"request": "launch",
"mainClass": "us.dot.its.jpo.ode.api.ConflictApiApplication",
"projectName": "intersection-api",
"env": {
"AUTH_SERVER_URL": "http://172.26.97.25:8084"
},
"envFile": "${workspaceFolder}/.env",
"preLaunchTask": "run-intersection-no-api"
"preLaunchTask": "run-intersection-no-api",
"env": {
"AUTH_SERVER_URL": "http://localhost:8084",
"KAFKA_BROKER_IP": "localhost",
"DB_HOST_IP": "localhost",
"PG_DB_PASS": "postgres",
"POSTGRES_SERVER_URL": "jdbc:postgresql://localhost:5432",
"CM_SERVER_URL": "http://localhost:8082",
"UNSUBSCRIBE_SECRET_KEY": "b5f9070ca58d4576ea6a2d8d4c1b97caf8abc2554198f8f9acf86d0d31a52a52",
"INTERSECTION_SMTP_USERNAME": "admin",
"INTERSECTION_SMTP_PASSWORD": "password",
"INTERSECTION_SMTP_AUTH": "true",
"INTERSECTION_SMTP_STARTTLS": "false"
}
}
],
"compounds": [
Expand Down
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@
"rwdata",
"rxtxfwd",
"SASL",
"secretmanager",
"Scms",
"secretmanager",
"SNMP",
"snmpcredential",
"snmperrorcheck",
Expand All @@ -119,6 +119,7 @@
"subquery",
"svcs",
"TABLENAME",
"Thymeleaf",
"timefield",
"toaddrs",
"txrxmsg",
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,12 @@ docker compose down -v
docker compose up -d
```

### SMTP Email Testing

For testing Intersection API email generation, a local SMTP server should be used. The recommended server is [smtp4dev](https://github.com/rnwood/smtp4dev).

This can be used by enabling the `smtp4dev` profile in the docker-compose-intersection.yml file. This will start smtp4dev on ports 5000 (web UI), 25 (SMTP), 143 (IMAP), and 110 (POP3).

## License Information

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
Expand Down
33 changes: 31 additions & 2 deletions docker-compose-intersection.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ services:
SPRING_DATA_MONGODB_DATABASE: ${CM_DATABASE_NAME:-CV}

KEYCLOAK_CLIENT_API_ID: ${KEYCLOAK_API_CLIENT_ID:-cvmanager-api}
KEYCLOAK_CLIENT_API_SECRET: ${KEYCLOAK_API_CLIENT_SECRET_KEY:-keycloak-secret-key}
KEYCLOAK_CLIENT_API_SECRET: ${KEYCLOAK_CLIENT_API_SECRET_KEY:-keycloak-secret-key}

KAFKA_BROKER_IP: ${KAFKA_BROKER_IP:-kafka}
KAFKA_BROKER_PORT: ${KAFKA_BROKER_PORT:-5432}
Expand All @@ -45,10 +45,25 @@ services:
POSTGRES_SERVER_URL: jdbc:postgresql://${PG_DB_HOST:-cvmanager_postgres:5432}

INTERSECTION_API_ENABLE_API: ${INTERSECTION_API_ENABLE_API:-True}
INTERSECTION_API_ENABLE_EMAILER: ${INTERSECTION_API_ENABLE_EMAILER:-false}
INTERSECTION_API_ENABLE_EMAILER: ${INTERSECTION_API_ENABLE_EMAILER:-true}
INTERSECTION_API_ENABLE_REPORTS: ${INTERSECTION_API_ENABLE_REPORTS:-false}
INTERSECTION_API_ENABLE_HAAS: ${INTERSECTION_API_ENABLE_HAAS:-false}
INTERSECTION_API_ENABLE_ASN1_DECODER: ${INTERSECTION_API_ENABLE_ASN1_DECODER:-true}

BASE_ROUTE_PREFIX: ${INTERSECTION_API_ROUTE_PREFIX:-/}

INTERSECTION_EMAIL_BROKER: ${INTERSECTION_EMAIL_BROKER:-SMTP}
INTERSECTION_SENDER_EMAIL: ${INTERSECTION_SENDER_EMAIL:-donotreply@cvmanager.com}
UNSUBSCRIBE_SECRET_KEY: ${UNSUBSCRIBE_SECRET_KEY:-b5f9070ca58d4576ea6a2d8d4c1b97caf8abc2554198f8f9acf86d0d31a52a52}
CV_MANAGER_FRONT_END_URI: ${CV_MANAGER_FRONT_END_URI:-http://localhost:${WEBAPP_PORT:-3000}}
Comment thread
jacob6838 marked this conversation as resolved.
INTERSECTION_SMTP_SERVER_HOST: ${INTERSECTION_SMTP_SERVER_HOST:-smtp4dev}
INTERSECTION_SMTP_SERVER_PORT: ${INTERSECTION_SMTP_SERVER_PORT:-1025}
INTERSECTION_SMTP_USERNAME: ${INTERSECTION_SMTP_USERNAME:-admin}
INTERSECTION_SMTP_PASSWORD: ${INTERSECTION_SMTP_PASSWORD:-password}
INTERSECTION_SMTP_AUTH: ${INTERSECTION_SMTP_AUTH_ENABLED:-true}
INTERSECTION_SMTP_STARTTLS: ${INTERSECTION_SMTP_STARTTLS_ENABLED:-false}
SENDGRID_API_KEY: ${SENDGRID_API_KEY}
POSTMARK_API_KEY: ${POSTMARK_API_KEY}
entrypoint:
- sh
- -c
Expand All @@ -68,3 +83,17 @@ services:
kafka-setup:
condition: service_started
required: false
smtp4dev:
profiles:
- smtp4dev
image: rnwood/smtp4dev:v3
restart: always
ports:
- '5000:80' # Web UI
Comment thread
John-Wiens marked this conversation as resolved.
- '25:25' # SMTP
environment:
# Enable SMTP authentication
- ServerOptions__AuthenticationRequired=true
# Set username and password for SMTP auth
- ServerOptions__Users__0__Username=${SMTP4DEV_USERNAME:-admin}
- ServerOptions__Users__0__Password=${SMTP4DEV_PASSWORD:-password}
22 changes: 18 additions & 4 deletions resources/sql_scripts/CVManager_CreateTables.sql
Original file line number Diff line number Diff line change
Expand Up @@ -428,9 +428,16 @@ CREATE SEQUENCE public.email_type_email_type_id_seq
CREATE TABLE IF NOT EXISTS public.email_type
(
email_type_id integer NOT NULL DEFAULT nextval('email_type_email_type_id_seq'::regclass),
CONSTRAINT email_type_pkey PRIMARY KEY (email_type_id),
email_type character varying(128) COLLATE pg_catalog.default NOT NULL,
CONSTRAINT email_type_unique UNIQUE (email_type)
description character varying(256) COLLATE pg_catalog.default,
supports_immediate boolean DEFAULT true NOT NULL,
supports_hourly boolean DEFAULT false NOT NULL,
supports_daily boolean DEFAULT false NOT NULL,
supports_weekly boolean DEFAULT false NOT NULL,
supports_monthly boolean DEFAULT false NOT NULL,
CONSTRAINT email_type_pkey PRIMARY KEY (email_type_id),
CONSTRAINT email_type_unique UNIQUE (email_type),
CONSTRAINT at_least_one_frequency CHECK (supports_immediate OR supports_hourly OR supports_daily OR supports_weekly OR supports_monthly)
);

CREATE SEQUENCE public.user_email_notification_user_email_notification_id_seq
Expand All @@ -445,15 +452,22 @@ CREATE TABLE IF NOT EXISTS public.user_email_notification
user_email_notification_id integer NOT NULL DEFAULT nextval('user_email_notification_user_email_notification_id_seq'::regclass),
user_id integer NOT NULL,
email_type_id integer NOT NULL,
immediate boolean DEFAULT true NOT NULL,
hourly boolean DEFAULT false NOT NULL,
daily boolean DEFAULT false NOT NULL,
weekly boolean DEFAULT false NOT NULL,
monthly boolean DEFAULT false NOT NULL,
CONSTRAINT user_email_notification_pkey PRIMARY KEY (user_email_notification_id),
CONSTRAINT user_email_notification_unique UNIQUE (user_id, email_type_id),
CONSTRAINT at_least_one_subscription CHECK (immediate OR hourly OR daily OR weekly OR monthly),
CONSTRAINT fk_user_id FOREIGN KEY (user_id)
REFERENCES public.users (user_id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION,
ON DELETE CASCADE,
CONSTRAINT fk_email_type_id FOREIGN KEY (email_type_id)
REFERENCES public.email_type (email_type_id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
ON DELETE CASCADE
);

CREATE SEQUENCE public.obu_ota_request_id_seq
Expand Down
19 changes: 17 additions & 2 deletions resources/sql_scripts/CVManager_SampleData.sql
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,23 @@ INSERT INTO public.snmp_msgfwd_config(
(2, 3, 2, 'SPAT', '10.0.0.80', 44910, '2024/04/01T00:00:00', '2034/04/01T00:00:00', '1', '0');

INSERT INTO public.email_type(
email_type)
VALUES ('Support Requests'), ('Firmware Upgrade Failures'), ('Daily Message Counts');
email_type, supports_immediate, supports_hourly, supports_daily, supports_weekly, supports_monthly)
VALUES ('Support Requests', true, false, false, false, false),
('Firmware Upgrade Failures', true, false, false, false, false),
('Daily Message Counts', true, false, false, false, false),
('Access Requests', true, false, false, false, false),
('Intersection Notification Summary', true, true, true, true, true),
('Critical Error Messages', true, false, false, false, false);

INSERT INTO public.user_email_notification(
user_email_notification_id, user_id, email_type_id, immediate, hourly, daily, weekly, monthly)
VALUES (1, 1, 1, true, false, false, false, false),
(2, 1, 2, true, false, false, false, false),
(3, 1, 3, true, false, false, false, false),
(4, 1, 4, true, false, false, false, false),
(5, 1, 5, true, true, true, true, true),
(6, 1, 6, true, false, false, false, false);


INSERT INTO public.intersections(
intersection_number, ref_pt, intersection_name)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
-- user_email_notification table changes
-- Add new columns to email_type table
ALTER TABLE public.email_type
ADD COLUMN IF NOT EXISTS description character varying(256),
ADD COLUMN IF NOT EXISTS supports_immediate boolean DEFAULT true NOT NULL,
ADD COLUMN IF NOT EXISTS supports_hourly boolean DEFAULT false NOT NULL,
ADD COLUMN IF NOT EXISTS supports_daily boolean DEFAULT false NOT NULL,
ADD COLUMN IF NOT EXISTS supports_weekly boolean DEFAULT false NOT NULL,
ADD COLUMN IF NOT EXISTS supports_monthly boolean DEFAULT false NOT NULL;

-- Add constraints to email_type (skip if already exists)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'email_type_unique') THEN
ALTER TABLE public.email_type ADD CONSTRAINT email_type_unique UNIQUE (email_type);
END IF;

IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'at_least_one_frequency') THEN
ALTER TABLE public.email_type ADD CONSTRAINT at_least_one_frequency
CHECK (supports_immediate OR supports_hourly OR supports_daily OR supports_weekly OR supports_monthly);
END IF;
END $$;


-- Insert or update email types with specific frequency settings
INSERT INTO public.email_type(email_type, supports_immediate, supports_hourly, supports_daily, supports_weekly, supports_monthly)
VALUES
('Support Requests', true, false, false, false, false),
('Firmware Upgrade Failures', true, false, false, false, false),
('Daily Message Counts', true, false, false, false, false),
('Access Requests', true, false, false, false, false),
('Intersection Notification Summary', true, true, true, true, true),
('Critical Error Messages', true, false, false, false, false)
ON CONFLICT (email_type)
DO UPDATE SET
supports_immediate = EXCLUDED.supports_immediate,
supports_hourly = EXCLUDED.supports_hourly,
supports_daily = EXCLUDED.supports_daily,
supports_weekly = EXCLUDED.supports_weekly,
supports_monthly = EXCLUDED.supports_monthly;



-- Add new columns to user_email_notification table
ALTER TABLE public.user_email_notification
ADD COLUMN IF NOT EXISTS immediate boolean DEFAULT true NOT NULL,
ADD COLUMN IF NOT EXISTS hourly boolean DEFAULT false NOT NULL,
ADD COLUMN IF NOT EXISTS daily boolean DEFAULT false NOT NULL,
ADD COLUMN IF NOT EXISTS weekly boolean DEFAULT false NOT NULL,
ADD COLUMN IF NOT EXISTS monthly boolean DEFAULT false NOT NULL;

-- Add constraints to user_email_notification (skip if already exists)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'user_email_notification_unique') THEN
ALTER TABLE public.user_email_notification ADD CONSTRAINT user_email_notification_unique UNIQUE (user_id, email_type_id);
END IF;

IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'at_least_one_subscription') THEN
ALTER TABLE public.user_email_notification ADD CONSTRAINT at_least_one_subscription
CHECK (immediate OR hourly OR daily OR weekly OR monthly);
END IF;
END $$;
12 changes: 8 additions & 4 deletions sample-full.env
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,15 @@ INTERSECTION_API_ROUTE_PREFIX="/"

# Email Configuration
INTERSECTION_EMAIL_BROKER="" # sendgrid, postmark, anything else will use generic SMTP mail server

# if EMAIL_BROKER is not set (SMTP):
INTERSECTION_SENDER_EMAIL=
INTERSECTION_SMTP_SERVER_IP=
INTERSECTION_SMTP_SERVER_PORT=1025

# if EMAIL_BROKER is SMTP:
INTERSECTION_SMTP_SERVER_HOST=smtp4dev
INTERSECTION_SMTP_SERVER_PORT=25
INTERSECTION_SMTP_USERNAME=admin
INTERSECTION_SMTP_PASSWORD=password
INTERSECTION_SMTP_AUTH_ENABLED=true
INTERSECTION_SMTP_STARTTLS_ENABLED=false

# if EMAIL_BROKER="sendgrid":
SENDGRID_USERNAME=
Expand Down
37 changes: 33 additions & 4 deletions services/intersection-api/api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@
<artifactId>kafka-clients</artifactId>
<version>3.2.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
Expand Down Expand Up @@ -201,6 +197,11 @@
<version>21.1.2</version>
<!-- Version should match Keycloak Version specified in Conflict Monitor Dockerfile -->
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.38</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
Expand All @@ -209,6 +210,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
Expand Down Expand Up @@ -240,12 +245,36 @@
<artifactId>sendgrid-java</artifactId>
<version>4.10.1</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>com.sun.activation</groupId>
<artifactId>javax.activation</artifactId>
<version>1.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.postmarkapp/postmark -->
<dependency>
<groupId>com.postmarkapp</groupId>
<artifactId>postmark</artifactId>
<version>1.11.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Comment thread
mcook42 marked this conversation as resolved.
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ public class ConflictMonitorApiProperties {
private String kafkaBrokers = null;
private static final String DEFAULT_KAFKA_PORT = "9092";
private String cmServerURL = "";
private String emailBroker = "";
private String emailFromAddress = "noreply@cimms.com";
private long mongoTimeoutMs = 5000;
private String hostId;
private List<Path> uploadLocations = new ArrayList<>();
Expand Down Expand Up @@ -146,24 +144,6 @@ public void setCmServerURL(String cmServerUrl) {
this.cmServerURL = cmServerUrl;
}

public String getEmailBroker() {
return emailBroker;
}

@Value("${emailBroker}")
public void setEmailBroker(String emailBroker) {
this.emailBroker = emailBroker;
}

public String getEmailFromAddress() {
return emailFromAddress;
}

@Value("${emailFromAddress}")
public void setEmailFromAddress(String emailFromAddress) {
this.emailFromAddress = emailFromAddress;
}

public long getMongoTimeoutMs() {
return mongoTimeoutMs;
}
Expand Down

This file was deleted.

Loading
Loading