Compare commits
124 Commits
49a6c755ee
...
8860340cc4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8860340cc4 | ||
|
|
553a61559c | ||
|
|
5440ed0ace | ||
|
|
35851c124c | ||
|
|
3cc0d40fa3 | ||
|
|
be65f4a5e6 | ||
|
|
3358a2693c | ||
|
|
62cda5c0cb | ||
|
|
7600cebcbb | ||
|
|
394469923b | ||
|
|
2da6049206 | ||
|
|
3cf2d2ef7a | ||
|
|
afd7b311a9 | ||
|
|
7ab21ae840 | ||
|
|
12c3a732e4 | ||
|
|
4d7da94315 | ||
|
|
80b9841aee | ||
|
|
00eb3f7aca | ||
|
|
825058f790 | ||
|
|
d5d245cfc1 | ||
|
|
ca19649b6a | ||
|
|
65bb5cd80a | ||
|
|
43b5fc03fd | ||
|
|
11a76e0292 | ||
|
|
a649b629e4 | ||
|
|
3efa83bc44 | ||
|
|
ef804b3896 | ||
|
|
f561a73b01 | ||
|
|
432fcbc503 | ||
|
|
b4e0f8c13b | ||
|
|
e216a763ac | ||
|
|
6091b7180f | ||
|
|
288ee6a2a6 | ||
|
|
a25c0bdf5d | ||
|
|
4ecb6625c8 | ||
|
|
174d0b136e | ||
|
|
d8f7464944 | ||
|
|
9f5003ecc5 | ||
|
|
cda9b648ad | ||
|
|
1af565ae1b | ||
|
|
36b03dea7b | ||
|
|
528a217708 | ||
|
|
d1a149e40d | ||
|
|
758e60ecb3 | ||
|
|
e06f5747ec | ||
|
|
0b1be38681 | ||
|
|
e9b4298f58 | ||
|
|
887295260f | ||
|
|
a06434642c | ||
|
|
36a1edfecf | ||
|
|
243573d4b2 | ||
|
|
41de6c1e8a | ||
|
|
0ab9430f35 | ||
|
|
20c2129d06 | ||
|
|
5430610b56 | ||
|
|
c91b2d7f3a | ||
|
|
3357267581 | ||
|
|
c6263e78b2 | ||
|
|
cf486796ac | ||
|
|
79f63ba9a5 | ||
|
|
fb5fa1b0ff | ||
|
|
6325d07909 | ||
|
|
04df491d64 | ||
|
|
f05a8b73ec | ||
|
|
1292d09427 | ||
|
|
5083a68205 | ||
|
|
8ecd9fcbda | ||
|
|
ff8f5f2c1a | ||
|
|
2ff6fcca17 | ||
|
|
d52bd8f94e | ||
|
|
ed74bb5e93 | ||
|
|
9857f053a1 | ||
|
|
e71d52be8a | ||
|
|
cad27f1842 | ||
|
|
d2000a46bc | ||
|
|
8e06e20b70 | ||
|
|
4c32043e5f | ||
|
|
8fff75dcf2 | ||
|
|
febd08821a | ||
|
|
d3dc37576d | ||
|
|
aef7a3aa30 | ||
|
|
815d6a9a4a | ||
|
|
853c3cf53e | ||
| 7fa3e4a545 | |||
| 836ce3527f | |||
| b174f77f6c | |||
| 0f5800441a | |||
| f5ee240283 | |||
| bde45e0dc9 | |||
| 5ab7d4f90d | |||
| b560240c17 | |||
| ec2efd4661 | |||
| c26264b92a | |||
| 9ff96cdf2f | |||
| 58b07e9e84 | |||
| 90ce6bc907 | |||
| b1295f4329 | |||
| 026eb05912 | |||
| 0a2ea083df | |||
| a11aa41cb2 | |||
| 7fbc9a2c96 | |||
| d570da4b0b | |||
| cd156de795 | |||
| b57d395fed | |||
| 05d4a4bc63 | |||
| 858ed6a0cf | |||
| 20cb782a63 | |||
| 94061891e3 | |||
| 075fda64f6 | |||
| c540518723 | |||
| fad11d56b8 | |||
| 7ce6abd3e7 | |||
| 97b0fb09f0 | |||
| 15a4936310 | |||
| 913e0dfcc1 | |||
| adb66611c1 | |||
| b0304034cb | |||
| 6c42429214 | |||
| 4f1957fe95 | |||
| 7cb9599eda | |||
| 48fc49db9c | |||
| 1aa76771c4 | |||
| afa52cb11c | |||
| 47854d8b39 |
4
.aiassistant/rules/rules.md
Normal file
4
.aiassistant/rules/rules.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
apply: always
|
||||
---
|
||||
|
||||
12
.aiignore
Normal file
12
.aiignore
Normal file
@@ -0,0 +1,12 @@
|
||||
# An .aiignore file follows the same syntax as a .gitignore file.
|
||||
# .gitignore documentation: https://git-scm.com/docs/gitignore
|
||||
|
||||
# you can ignore files
|
||||
.DS_Store
|
||||
*.log
|
||||
*.tmp
|
||||
|
||||
# or folders
|
||||
dist/
|
||||
build/
|
||||
out/
|
||||
226
docs/EMAIL_CONFIGURATION.md
Normal file
226
docs/EMAIL_CONFIGURATION.md
Normal file
@@ -0,0 +1,226 @@
|
||||
# Email Notification Configuration Guide
|
||||
|
||||
## Overview
|
||||
The application uses Gmail SMTP to send email notifications for auction alerts and lot updates.
|
||||
|
||||
## Gmail App Password Setup (Required for michael@appmodel.nl)
|
||||
|
||||
### Why App Passwords?
|
||||
Google requires **App Passwords** instead of your regular Gmail password when using SMTP with 2-factor authentication enabled.
|
||||
|
||||
### Steps to Generate Gmail App Password:
|
||||
|
||||
1. **Enable 2-Factor Authentication** (if not already enabled)
|
||||
- Go to https://myaccount.google.com/security
|
||||
- Under "Signing in to Google", enable "2-Step Verification"
|
||||
|
||||
2. **Generate App Password**
|
||||
- Go to https://myaccount.google.com/apppasswords
|
||||
- Or navigate: Google Account → Security → 2-Step Verification → App passwords
|
||||
- Select app: "Mail"
|
||||
- Select device: "Other (Custom name)" → Enter "Auctiora Monitor"
|
||||
- Click "Generate"
|
||||
- Google will display a 16-character password (e.g., `abcd efgh ijkl mnop`)
|
||||
- **Copy this password immediately** (you won't see it again)
|
||||
|
||||
3. **Use the App Password**
|
||||
- Use this 16-character password (without spaces) in your configuration
|
||||
- Format: `abcdefghijklmnop`
|
||||
|
||||
## Configuration
|
||||
|
||||
### Method 1: Environment Variable (Recommended for Production)
|
||||
|
||||
Set the `auction.notification.config` property in your `application.properties` or via environment variable:
|
||||
|
||||
```properties
|
||||
# Format: smtp:username:password:recipient_email
|
||||
auction.notification.config=smtp:michael@appmodel.nl:YOUR_APP_PASSWORD:michael@appmodel.nl
|
||||
```
|
||||
|
||||
**Example with Docker:**
|
||||
```bash
|
||||
docker run -e AUCTION_NOTIFICATION_CONFIG="smtp:michael@appmodel.nl:abcdefghijklmnop:michael@appmodel.nl" ...
|
||||
```
|
||||
|
||||
### Method 2: application.properties (Development)
|
||||
|
||||
Edit `src/main/resources/application.properties`:
|
||||
|
||||
```properties
|
||||
# BEFORE (desktop only):
|
||||
auction.notification.config=desktop
|
||||
|
||||
# AFTER (desktop + email):
|
||||
auction.notification.config=smtp:michael@appmodel.nl:YOUR_APP_PASSWORD_HERE:michael@appmodel.nl
|
||||
```
|
||||
|
||||
### Format Breakdown
|
||||
|
||||
The configuration string format is:
|
||||
```
|
||||
smtp:<SMTP_USERNAME>:<APP_PASSWORD>:<RECIPIENT_EMAIL>
|
||||
```
|
||||
|
||||
Where:
|
||||
- `SMTP_USERNAME`: Your Gmail address (michael@appmodel.nl)
|
||||
- `APP_PASSWORD`: The 16-character app password from Google (no spaces)
|
||||
- `RECIPIENT_EMAIL`: Email address to receive notifications (can be same as sender)
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
### Desktop Notifications Only
|
||||
```properties
|
||||
auction.notification.config=desktop
|
||||
```
|
||||
|
||||
### Email Notifications Only
|
||||
```properties
|
||||
auction.notification.config=smtp:michael@appmodel.nl:abcdefghijklmnop:michael@appmodel.nl
|
||||
```
|
||||
|
||||
### Both Desktop and Email (Recommended)
|
||||
The SMTP configuration automatically enables both:
|
||||
```properties
|
||||
auction.notification.config=smtp:michael@appmodel.nl:abcdefghijklmnop:michael@appmodel.nl
|
||||
```
|
||||
|
||||
### Send to Multiple Recipients
|
||||
To send to multiple recipients, you can modify the code or set up Gmail forwarding rules.
|
||||
|
||||
## SMTP Configuration Details
|
||||
|
||||
The application uses these Gmail SMTP settings (hardcoded):
|
||||
- **Host**: smtp.gmail.com
|
||||
- **Port**: 587
|
||||
- **Security**: STARTTLS
|
||||
- **Authentication**: Required
|
||||
|
||||
## Testing Configuration
|
||||
|
||||
After configuration, restart the application and check logs:
|
||||
|
||||
**Success:**
|
||||
```
|
||||
✓ OpenCV loaded successfully
|
||||
Email notification: Test Alert
|
||||
```
|
||||
|
||||
**Failure (wrong password):**
|
||||
```
|
||||
WARN NotificationService - Email failed: 535-5.7.8 Username and Password not accepted
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Error: "Username and Password not accepted"
|
||||
- **Cause**: Invalid App Password or 2FA not enabled
|
||||
- **Solution**:
|
||||
1. Verify 2-Factor Authentication is enabled
|
||||
2. Generate a new App Password
|
||||
3. Ensure no spaces in the password
|
||||
4. Check for typos in email address
|
||||
|
||||
### Error: "AuthenticationFailedException"
|
||||
- **Cause**: Incorrect credentials format
|
||||
- **Solution**: Verify the format: `smtp:user:pass:recipient`
|
||||
|
||||
### Gmail Blocks Sign-in
|
||||
- **Cause**: "Less secure app access" is disabled (deprecated by Google)
|
||||
- **Solution**: Use App Passwords (as described above)
|
||||
|
||||
### Configuration Not Taking Effect
|
||||
- **Cause**: Application not restarted or environment variable not set
|
||||
- **Solution**:
|
||||
1. Restart the application/container
|
||||
2. Verify with: `docker logs auctiora | grep notification`
|
||||
|
||||
### SMTP Connection Timeout
|
||||
- **Error**: `Couldn't connect to host, port: smtp.gmail.com, 587; timeout -1`
|
||||
- **Causes**:
|
||||
1. **Firewall/Network blocking port 587**
|
||||
2. **Corporate network blocking SMTP**
|
||||
3. **Antivirus/security software blocking connections**
|
||||
4. **No internet access in test/container environment**
|
||||
- **Solutions**:
|
||||
1. **Test connectivity**:
|
||||
```bash
|
||||
# On Linux/Mac
|
||||
telnet smtp.gmail.com 587
|
||||
# On Windows
|
||||
Test-NetConnection -ComputerName smtp.gmail.com -Port 587
|
||||
```
|
||||
2. **Check firewall rules**: Allow outbound connections to port 587
|
||||
3. **Docker network**: Ensure container has internet access
|
||||
```bash
|
||||
docker exec auctiora ping -c 3 smtp.gmail.com
|
||||
```
|
||||
4. **Try alternative port 465** (SSL/TLS):
|
||||
- Requires code change to use `mail.smtp.socketFactory`
|
||||
5. **Corporate networks**: May require VPN or proxy configuration
|
||||
6. **Windows Firewall**: Add Java/application to allowed programs
|
||||
|
||||
### Connection Succeeds but Authentication Fails
|
||||
- **Error**: `Email authentication failed - check Gmail App Password`
|
||||
- **Solution**: Verify App Password is correct and has no spaces
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Never commit passwords to git**
|
||||
- Use environment variables in production
|
||||
- Add `application-local.properties` to `.gitignore`
|
||||
|
||||
2. **Rotate App Passwords periodically**
|
||||
- Generate new App Password every 90 days
|
||||
- Revoke old passwords at https://myaccount.google.com/apppasswords
|
||||
|
||||
3. **Use separate App Passwords per application**
|
||||
- Creates "Auctiora Monitor" specific password
|
||||
- Easy to revoke if compromised
|
||||
|
||||
4. **Monitor Gmail Activity**
|
||||
- Check https://myaccount.google.com/notifications
|
||||
- Review "Recent security activity"
|
||||
|
||||
## Example Docker Compose Configuration
|
||||
|
||||
```yaml
|
||||
services:
|
||||
auctiora:
|
||||
image: auctiora:latest
|
||||
environment:
|
||||
- AUCTION_NOTIFICATION_CONFIG=smtp:michael@appmodel.nl:${GMAIL_APP_PASSWORD}:michael@appmodel.nl
|
||||
- AUCTION_DATABASE_PATH=/mnt/okcomputer/output/cache.db
|
||||
volumes:
|
||||
- shared-auction-data:/mnt/okcomputer/output
|
||||
```
|
||||
|
||||
Then set the password in `.env` file (not committed):
|
||||
```bash
|
||||
GMAIL_APP_PASSWORD=abcdefghijklmnop
|
||||
```
|
||||
|
||||
## Notification Types
|
||||
|
||||
The application sends these email notifications:
|
||||
|
||||
1. **Lot Closing Soon** (Priority: High)
|
||||
- Sent when a lot closes within 5 minutes
|
||||
- Subject: `[Troostwijk] Lot nearing closure`
|
||||
|
||||
2. **Bid Updated** (Priority: Normal)
|
||||
- Sent when current bid increases
|
||||
- Subject: `[Troostwijk] Bid update`
|
||||
|
||||
3. **Critical Alerts** (Priority: High)
|
||||
- System errors or important events
|
||||
- Subject: `[Troostwijk] Critical Alert`
|
||||
|
||||
## Alternative: Desktop Notifications Only
|
||||
|
||||
If you don't want email notifications, use:
|
||||
```properties
|
||||
auction.notification.config=desktop
|
||||
```
|
||||
|
||||
This will only show system tray notifications (Linux/Windows/Mac).
|
||||
33
scripts/BFG.ps1
Normal file
33
scripts/BFG.ps1
Normal file
@@ -0,0 +1,33 @@
|
||||
# BFG.ps1 (run from C:\vibe\auctiora\scripts)
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# 1) Download BFG jar once, next to this script
|
||||
$bfgJar = Join-Path $PSScriptRoot "bfg.jar"
|
||||
if (-not (Test-Path $bfgJar)) {
|
||||
Invoke-WebRequest `
|
||||
"https://repo1.maven.org/maven2/com/madgag/bfg/1.14.0/bfg-1.14.0.jar" `
|
||||
-OutFile $bfgJar
|
||||
}
|
||||
|
||||
# 2) Clone bare mirror next to project root: C:\vibe\auctiora\auctiora.git
|
||||
$rootDir = Join-Path $PSScriptRoot ".."
|
||||
$mirrorPath = Join-Path $rootDir "auctiora.git"
|
||||
|
||||
if (Test-Path $mirrorPath) {
|
||||
Remove-Item $mirrorPath -Recurse -Force
|
||||
}
|
||||
|
||||
git clone --mirror "https://git.appmodel.nl/Tour/auctiora.git" $mirrorPath
|
||||
|
||||
# 3) Run BFG in mirror
|
||||
Push-Location $mirrorPath
|
||||
|
||||
java -jar $bfgJar --strip-blobs-bigger-than 50M .
|
||||
|
||||
git reflog expire --expire=now --all
|
||||
git gc --prune=now --aggressive
|
||||
|
||||
# 4) Force-push cleaned history
|
||||
git push --force
|
||||
|
||||
Pop-Location
|
||||
@@ -26,7 +26,7 @@ public record ImageProcessingService(DatabaseService db, ObjectDetectionService
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("Process fail {}: {}", id, e.getMessage());
|
||||
log.warn("Process fail {}: {}", id, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@ public record ImageProcessingService(DatabaseService db, ObjectDetectionService
|
||||
log.info("Processed {}, detected {}", processed, detected);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Batch fail: {}", e.getMessage());
|
||||
log.warn("Batch fail: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
package auctiora;
|
||||
|
||||
import javax.mail.Authenticator;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.PasswordAuthentication;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Transport;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.mail.*;
|
||||
import javax.mail.internet.*;
|
||||
import java.awt.*;
|
||||
import java.awt.SystemTray;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.TrayIcon;
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -52,32 +59,43 @@ public record NotificationService(Config cfg) {
|
||||
var props = new Properties();
|
||||
props.put("mail.smtp.auth", "true");
|
||||
props.put("mail.smtp.starttls.enable", "true");
|
||||
props.put("mail.smtp.starttls.required", "true");
|
||||
props.put("mail.smtp.host", "smtp.gmail.com");
|
||||
props.put("mail.smtp.port", "587");
|
||||
props.put("mail.smtp.ssl.trust", "smtp.gmail.com");
|
||||
|
||||
props.put("mail.smtp.ssl.protocols", "TLSv1.2");
|
||||
|
||||
// Connection timeouts (10 seconds each)
|
||||
props.put("mail.smtp.connectiontimeout", "10000");
|
||||
props.put("mail.smtp.timeout", "10000");
|
||||
props.put("mail.smtp.writetimeout", "10000");
|
||||
|
||||
var session = Session.getInstance(props, new Authenticator() {
|
||||
|
||||
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(cfg.smtpUsername(), cfg.smtpPassword());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var m = new MimeMessage(session);
|
||||
m.setFrom(new InternetAddress(cfg.smtpUsername()));
|
||||
m.setRecipients(Message.RecipientType.TO, InternetAddress.parse(cfg.toEmail()));
|
||||
m.setSubject("[Troostwijk] " + title);
|
||||
m.setText(msg);
|
||||
m.setSentDate(new Date());
|
||||
|
||||
|
||||
if (prio > 0) {
|
||||
m.setHeader("X-Priority", "1");
|
||||
m.setHeader("Importance", "High");
|
||||
}
|
||||
|
||||
|
||||
Transport.send(m);
|
||||
log.info("Email notification: {}", title);
|
||||
log.info("Email notification sent: {}", title);
|
||||
} catch (javax.mail.AuthenticationFailedException e) {
|
||||
log.warn("Email authentication failed - check Gmail App Password: {}", e.getMessage());
|
||||
} catch (javax.mail.MessagingException e) {
|
||||
log.warn("Email connection failed (network/firewall issue?): {}", e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.warn("Email failed: {}", e.getMessage());
|
||||
}
|
||||
|
||||
@@ -56,12 +56,12 @@ public class AuctionRepository {
|
||||
|
||||
} catch (Exception e) {
|
||||
// If UNIQUE constraint on url fails, try updating by url
|
||||
String errMsg = e.getMessage();
|
||||
var errMsg = e.getMessage();
|
||||
if (errMsg != null && (errMsg.contains("UNIQUE constraint failed") ||
|
||||
errMsg.contains("PRIMARY KEY constraint failed"))) {
|
||||
log.debug("Auction conflict detected, attempting update by URL: {}", auction.url());
|
||||
|
||||
int updated = handle.createUpdate("""
|
||||
var updated = handle.createUpdate("""
|
||||
UPDATE auctions SET
|
||||
auction_id = :auctionId,
|
||||
title = :title,
|
||||
@@ -102,7 +102,7 @@ public class AuctionRepository {
|
||||
return jdbi.withHandle(handle ->
|
||||
handle.createQuery("SELECT * FROM auctions")
|
||||
.map((rs, ctx) -> {
|
||||
String closingStr = rs.getString("closing_time");
|
||||
var closingStr = rs.getString("closing_time");
|
||||
LocalDateTime closingTime = null;
|
||||
if (closingStr != null && !closingStr.isBlank()) {
|
||||
try {
|
||||
@@ -136,7 +136,7 @@ public class AuctionRepository {
|
||||
handle.createQuery("SELECT * FROM auctions WHERE country = :country")
|
||||
.bind("country", countryCode)
|
||||
.map((rs, ctx) -> {
|
||||
String closingStr = rs.getString("closing_time");
|
||||
var closingStr = rs.getString("closing_time");
|
||||
LocalDateTime closingTime = null;
|
||||
if (closingStr != null && !closingStr.isBlank()) {
|
||||
try {
|
||||
|
||||
@@ -14,14 +14,14 @@ class NotificationServiceTest {
|
||||
@Test
|
||||
@DisplayName("Should initialize with desktop-only configuration")
|
||||
void testDesktopOnlyConfiguration() {
|
||||
NotificationService service = new NotificationService("desktop");
|
||||
var service = new NotificationService("desktop");
|
||||
assertNotNull(service);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Should initialize with SMTP configuration")
|
||||
void testSMTPConfiguration() {
|
||||
NotificationService service = new NotificationService(
|
||||
var service = new NotificationService(
|
||||
"smtp:test@gmail.com:app_password:recipient@example.com"
|
||||
);
|
||||
assertNotNull(service);
|
||||
@@ -52,7 +52,7 @@ class NotificationServiceTest {
|
||||
@Test
|
||||
@DisplayName("Should send desktop notification without error")
|
||||
void testDesktopNotification() {
|
||||
NotificationService service = new NotificationService("desktop");
|
||||
var service = new NotificationService("desktop");
|
||||
|
||||
// Should not throw exception even if system tray not available
|
||||
assertDoesNotThrow(() ->
|
||||
@@ -63,7 +63,7 @@ class NotificationServiceTest {
|
||||
@Test
|
||||
@DisplayName("Should send high priority notification")
|
||||
void testHighPriorityNotification() {
|
||||
NotificationService service = new NotificationService("desktop");
|
||||
var service = new NotificationService("desktop");
|
||||
|
||||
assertDoesNotThrow(() ->
|
||||
service.sendNotification("Urgent message", "High Priority", 1)
|
||||
@@ -73,7 +73,7 @@ class NotificationServiceTest {
|
||||
@Test
|
||||
@DisplayName("Should send normal priority notification")
|
||||
void testNormalPriorityNotification() {
|
||||
NotificationService service = new NotificationService("desktop");
|
||||
var service = new NotificationService("desktop");
|
||||
|
||||
assertDoesNotThrow(() ->
|
||||
service.sendNotification("Regular message", "Normal Priority", 0)
|
||||
@@ -83,7 +83,7 @@ class NotificationServiceTest {
|
||||
@Test
|
||||
@DisplayName("Should handle notification when system tray not supported")
|
||||
void testNoSystemTraySupport() {
|
||||
NotificationService service = new NotificationService("desktop");
|
||||
var service = new NotificationService("desktop");
|
||||
|
||||
// Should gracefully handle missing system tray
|
||||
assertDoesNotThrow(() ->
|
||||
@@ -96,7 +96,7 @@ class NotificationServiceTest {
|
||||
void testEmailNotificationWithValidConfig() {
|
||||
// Note: This won't actually send email without valid credentials
|
||||
// But it should initialize properly
|
||||
NotificationService service = new NotificationService(
|
||||
var service = new NotificationService(
|
||||
"smtp:test@gmail.com:fake_password:test@example.com"
|
||||
);
|
||||
|
||||
@@ -112,7 +112,7 @@ class NotificationServiceTest {
|
||||
@Test
|
||||
@DisplayName("Should include both desktop and email when SMTP configured")
|
||||
void testBothNotificationChannels() {
|
||||
NotificationService service = new NotificationService(
|
||||
var service = new NotificationService(
|
||||
"smtp:user@gmail.com:password:recipient@example.com"
|
||||
);
|
||||
|
||||
@@ -125,7 +125,7 @@ class NotificationServiceTest {
|
||||
@Test
|
||||
@DisplayName("Should handle empty message gracefully")
|
||||
void testEmptyMessage() {
|
||||
NotificationService service = new NotificationService("desktop");
|
||||
var service = new NotificationService("desktop");
|
||||
|
||||
assertDoesNotThrow(() ->
|
||||
service.sendNotification("", "", 0)
|
||||
@@ -135,9 +135,9 @@ class NotificationServiceTest {
|
||||
@Test
|
||||
@DisplayName("Should handle very long message")
|
||||
void testLongMessage() {
|
||||
NotificationService service = new NotificationService("desktop");
|
||||
|
||||
String longMessage = "A".repeat(1000);
|
||||
var service = new NotificationService("desktop");
|
||||
|
||||
var longMessage = "A".repeat(1000);
|
||||
assertDoesNotThrow(() ->
|
||||
service.sendNotification(longMessage, "Long Message Test", 0)
|
||||
);
|
||||
@@ -146,7 +146,7 @@ class NotificationServiceTest {
|
||||
@Test
|
||||
@DisplayName("Should handle special characters in message")
|
||||
void testSpecialCharactersInMessage() {
|
||||
NotificationService service = new NotificationService("desktop");
|
||||
var service = new NotificationService("desktop");
|
||||
|
||||
assertDoesNotThrow(() ->
|
||||
service.sendNotification(
|
||||
@@ -184,10 +184,10 @@ class NotificationServiceTest {
|
||||
@Test
|
||||
@DisplayName("Should handle multiple rapid notifications")
|
||||
void testRapidNotifications() {
|
||||
NotificationService service = new NotificationService("desktop");
|
||||
var service = new NotificationService("desktop");
|
||||
|
||||
assertDoesNotThrow(() -> {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
for (var i = 0; i < 5; i++) {
|
||||
service.sendNotification("Notification " + i, "Rapid Test", 0);
|
||||
}
|
||||
});
|
||||
@@ -205,10 +205,10 @@ class NotificationServiceTest {
|
||||
@Test
|
||||
@DisplayName("Should send bid change notification format")
|
||||
void testBidChangeNotificationFormat() {
|
||||
NotificationService service = new NotificationService("desktop");
|
||||
|
||||
String message = "Nieuw bod op kavel 12345: €150.00 (was €125.00)";
|
||||
String title = "Kavel bieding update";
|
||||
var service = new NotificationService("desktop");
|
||||
|
||||
var message = "Nieuw bod op kavel 12345: €150.00 (was €125.00)";
|
||||
var title = "Kavel bieding update";
|
||||
|
||||
assertDoesNotThrow(() ->
|
||||
service.sendNotification(message, title, 0)
|
||||
@@ -218,10 +218,10 @@ class NotificationServiceTest {
|
||||
@Test
|
||||
@DisplayName("Should send closing alert notification format")
|
||||
void testClosingAlertNotificationFormat() {
|
||||
NotificationService service = new NotificationService("desktop");
|
||||
|
||||
String message = "Kavel 12345 sluit binnen 5 min.";
|
||||
String title = "Lot nearing closure";
|
||||
var service = new NotificationService("desktop");
|
||||
|
||||
var message = "Kavel 12345 sluit binnen 5 min.";
|
||||
var title = "Lot nearing closure";
|
||||
|
||||
assertDoesNotThrow(() ->
|
||||
service.sendNotification(message, title, 1)
|
||||
@@ -231,10 +231,10 @@ class NotificationServiceTest {
|
||||
@Test
|
||||
@DisplayName("Should send object detection notification format")
|
||||
void testObjectDetectionNotificationFormat() {
|
||||
NotificationService service = new NotificationService("desktop");
|
||||
|
||||
String message = "Lot contains: car, truck, machinery\nEstimated value: €5000";
|
||||
String title = "Object Detected";
|
||||
var service = new NotificationService("desktop");
|
||||
|
||||
var message = "Lot contains: car, truck, machinery\nEstimated value: €5000";
|
||||
var title = "Object Detected";
|
||||
|
||||
assertDoesNotThrow(() ->
|
||||
service.sendNotification(message, title, 0)
|
||||
|
||||
Reference in New Issue
Block a user