Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mail user on TransactionStop and SuspendedEV event #1263

Open
wants to merge 50 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
0005fa7
StringUtils: add method to check mail address
Aug 2, 2023
4cbea6f
UserRepository: add method "User.Details getDetails(String ocppTag)"
Aug 2, 2023
75fd4fa
TransactionRepository: add method "Transaction getTransaction(int tra…
Aug 2, 2023
e254786
MailService: change method "send(String subject, String body)" to "se…
Aug 2, 2023
4eadaa8
NotificationService: in method "ocppTransactionEnded(OcppTransactionE…
Aug 2, 2023
dd6fc78
Merge branch 'steve-community:master' into MailUserAtTransactionStop
fnkbsi Aug 2, 2023
1b366b4
OcppStationStatusSuspendedEV.java added
Aug 2, 2023
e38a108
NotificationFeature.java: added NotificationFeature "OcppStationStatu…
Aug 2, 2023
f51a3da
CentralSystemService16_Service.java: on a statusNotification, added p…
Aug 2, 2023
df0b5c4
OcppServerRepository: add method getConnectorPK
Aug 2, 2023
7f73ecd
TransactionRepository: add method getOcppTagOfActiveTransaction(integ…
Aug 2, 2023
4ca23a6
NotificationService: added Event ocppStationStatusSuspendedEV(OcppSta…
Aug 2, 2023
64707ee
NotificationService & CentralSystemService16_Service: Format and Comm…
Aug 4, 2023
00853ff
NotificationService: added mail to "admin" in OcppStationStatusSuspen…
Aug 5, 2023
bf113ab
NotificationService: formated mail text in OcppStationStatusSuspended…
Aug 5, 2023
4392296
NotificationService.java & OcppStationStatusSuspend: commeting and fo…
Oct 12, 2023
fac303d
Merge branch 'steve-community:master' into MailUserAtTransactionStop
fnkbsi Oct 12, 2023
ee0e608
Merge origin/MailUserAtTransactionStop into MailUserAtTransactionStop
Oct 12, 2023
8e44e38
style correction
Oct 12, 2023
472b75d
style correction
Oct 17, 2023
a38d588
Merge branch 'steve-community:master' into MailUserAtTransactionStop
fnkbsi Nov 28, 2023
d1f586d
Merge branch 'steve-community:master' into MailUserAtTransactionStop
fnkbsi Dec 13, 2023
416c838
Merge branch 'steve-community:master' into MailUserAtTransactionStop
fnkbsi Dec 23, 2023
953abb4
TransactionRepositoryImpl, method getOcppTagOfActiveTransaction: orde…
Dec 23, 2023
48d7a68
NotificationService, SuspendedEV & TransactionStop: catch exception i…
Dec 23, 2023
6a2a702
Removed unnecessary code
Dec 25, 2023
eb64190
NotificationService: shorten the error log message (no stack info)
Dec 25, 2023
102ea16
BeanConfiguration: add @EnableAsync to activate @Async in Notificatio…
Dec 25, 2023
1798ba9
BeanConfiguration: removed @EnableAsync because it's notcompiling und…
Dec 26, 2023
14ac662
NotificationService: removing @Async annotations. Realizing async ins…
Dec 26, 2023
817bc5d
Merge branch 'steve-community:master' into MailUserAtTransactionStop
fnkbsi Jan 15, 2024
6a9091c
OcppServerRepository remove method getConnectorPk
Jan 23, 2024
3d26aa2
TransactionRepository: add method getActiveTransactionId(String chage…
Jan 23, 2024
4c66f00
add timestamp to SUSPENDED_EV notification
Jan 23, 2024
4d2963a
adapt methode notificationActionSuspendedEV -> removed ocppServerRepo…
Jan 23, 2024
230c1ee
getActiveTransactionId(String chargeBox, Integer connectorId) method,…
Jan 23, 2024
a1d5ce1
Merge origin/MailUserAtTransactionStop into MailUserAtTransactionStop
Jan 23, 2024
f7919f7
Merge branch 'steve-community:master' into MailUserAtTransactionStop
fnkbsi Feb 1, 2024
2c46260
Merge branch 'steve-community:master' into MailUserAtTransactionStop
fnkbsi Feb 6, 2024
0563e46
Merge branch 'steve-community:master' into MailUserAtTransactionStop
fnkbsi Feb 19, 2024
26442d3
Merge branch 'steve-community:master' into MailUserAtTransactionStop
fnkbsi Mar 28, 2024
f61a428
Merge branch 'master' into MailUserAtTransactionStop
fnkbsi Apr 3, 2024
9faa7b4
Restore @override annotation after reslove conflict
fnkbsi Apr 3, 2024
a85bbef
Merge branch 'steve-community:master' into MailUserAtTransactionStop
fnkbsi Apr 19, 2024
199b45c
Merge branch 'steve-community:master' into MailUserAtTransactionStop
fnkbsi May 13, 2024
f5edb5d
Merge branch 'steve-community:master' into MailUserAtTransactionStop
fnkbsi Jun 19, 2024
22ba398
Merge branch 'steve-community:master' into MailUserAtTransactionStop
fnkbsi Aug 8, 2024
b2c6908
Adding user individual notification selection. Selection is stored in…
fnkbsi Aug 8, 2024
ac38d1e
Rename db migration script V1_06 to V1_08
fnkbsi Oct 10, 2024
b015a57
Merge origin/master into MailUserAtTransactionStop
fnkbsi Oct 10, 2024
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
1 change: 1 addition & 0 deletions src/main/java/de/rwth/idsg/steve/NotificationFeature.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public enum NotificationFeature {
OcppStationWebSocketConnected(" a JSON charging station connects"),
OcppStationWebSocketDisconnected(" a JSON charging station disconnects"),
OcppTransactionStarted(" a charging station starts a transaction"),
OcppStationStatusSuspendedEV(" a EV suspended charging"),
OcppTransactionEnded(" a charging station ends a transaction");


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@
* @since 19.08.2014
*/
public interface TransactionRepository {
Transaction getTransaction(int transactionPk);

List<Transaction> getTransactions(TransactionQueryForm form);

void writeTransactionsCSV(TransactionQueryForm form, Writer writer);

List<Integer> getActiveTransactionIds(String chargeBoxId);
Integer getActiveTransactionId(String chargeBoxId, Integer connectorId);

TransactionDetails getDetails(int transactionPk);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
public interface UserRepository {
List<User.Overview> getOverview(UserQueryForm form);
User.Details getDetails(int userPk);
User.Details getDetails(String ocppTag);

void add(UserForm form);
void update(UserForm form);
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/de/rwth/idsg/steve/repository/dto/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.rwth.idsg.steve.repository.dto;

import java.util.List;
import jooq.steve.db.tables.records.AddressRecord;
import jooq.steve.db.tables.records.UserRecord;
import lombok.Builder;
Expand All @@ -36,13 +36,14 @@ public class User {
public static final class Overview {
private final Integer userPk, ocppTagPk;
private final String ocppIdTag, name, phone, email;
private final List<UserNotificationFeature> enabledFeatures;
}

@Getter
@Builder
public static final class Details {
private final UserRecord userRecord;
private final AddressRecord address;
private Optional<String> ocppIdTag;
private final Optional<String> ocppIdTag;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*

Check failure on line 1 in src/main/java/de/rwth/idsg/steve/repository/dto/UserNotificationFeature.java

View workflow job for this annotation

GitHub Actions / checkstyle

[checkstyle] reported by reviewdog 🐶 File does not end with a newline. Raw Output: /github/workspace/./src/main/java/de/rwth/idsg/steve/repository/dto/UserNotificationFeature.java:1:0: error: File does not end with a newline. (com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck)
* SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve
* Copyright (C) 2013-2024 SteVe Community Team
* All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package de.rwth.idsg.steve.repository.dto;

//import static de.rwth.idsg.steve.utils.StringUtils.joinByComma;
//import static de.rwth.idsg.steve.utils.StringUtils.splitByComma;
//import java.util.List;
//import java.util.stream.Collectors;
import static de.rwth.idsg.steve.utils.StringUtils.joinByComma;
import static de.rwth.idsg.steve.utils.StringUtils.splitByComma;
import java.util.List;
import java.util.stream.Collectors;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

/**
*
* @author fnkbsi
*/
@RequiredArgsConstructor
public enum UserNotificationFeature {

// Ocpp related
//
//OcppStationBooted(" a charging station sends a boot notification (Note: This activates notifications about failed connection attempts for unregistered JSON stations, as well)"),

Check failure on line 42 in src/main/java/de/rwth/idsg/steve/repository/dto/UserNotificationFeature.java

View workflow job for this annotation

GitHub Actions / checkstyle

[checkstyle] reported by reviewdog 🐶 Line is longer than 120 characters (found 183). Raw Output: /github/workspace/./src/main/java/de/rwth/idsg/steve/repository/dto/UserNotificationFeature.java:42:0: error: Line is longer than 120 characters (found 183). (com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck)
OcppStationStatusFailure(" a connector gets faulted"),
//OcppStationWebSocketConnected(" a JSON charging station connects"),
//OcppStationWebSocketDisconnected(" a JSON charging station disconnects"),
OcppTransactionStarted(" a charging station starts a transaction"),
OcppStationStatusSuspendedEV(" a EV suspended charging"),
OcppTransactionEnded(" a charging station ends a transaction");


@Getter
private final String text;

public static UserNotificationFeature fromName(String v) {
for (UserNotificationFeature c: UserNotificationFeature.values()) {
if (c.name().equalsIgnoreCase(v)) {
return c;
}
}
throw new IllegalArgumentException(v);
}

public static List<UserNotificationFeature> splitFeatures(String str) {
return splitByComma(str).stream()
.map(UserNotificationFeature::fromName)
.collect(Collectors.toList());
}

public static String joinFeatures(List<UserNotificationFeature> enablesFeatures) {
return joinByComma(enablesFeatures);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ public TransactionRepositoryImpl(DSLContext ctx) {
this.ctx = ctx;
}

@Override
public Transaction getTransaction(int transactionPk) {
TransactionQueryForm form = new TransactionQueryForm();
form.setTransactionPk(transactionPk);
form.setReturnCSV(false);
form.setType(TransactionQueryForm.QueryType.ALL);
return getInternal(form).fetch()
.map(new TransactionMapper()).get(0);
}

@Override
public List<Transaction> getTransactions(TransactionQueryForm form) {
return getInternal(form).fetch()
Expand All @@ -89,6 +99,19 @@ public List<Integer> getActiveTransactionIds(String chargeBoxId) {
.fetch(TRANSACTION.TRANSACTION_PK);
}

@Override
public Integer getActiveTransactionId(String chargeBoxId, Integer connectorId) {
return ctx.select(TRANSACTION.TRANSACTION_PK)
.from(TRANSACTION)
.join(CONNECTOR)
.on(TRANSACTION.CONNECTOR_PK.equal(CONNECTOR.CONNECTOR_PK))
.and(CONNECTOR.CHARGE_BOX_ID.equal(chargeBoxId))
.where(TRANSACTION.STOP_TIMESTAMP.isNull())
.and(CONNECTOR.CONNECTOR_ID.equal(connectorId))
.orderBy(TRANSACTION.TRANSACTION_PK.desc()) // to avoid fetching ghost transactions, fetch the latest
.fetchAny(TRANSACTION.TRANSACTION_PK);
}

@Override
public TransactionDetails getDetails(int transactionPk) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import de.rwth.idsg.steve.repository.AddressRepository;
import de.rwth.idsg.steve.repository.UserRepository;
import de.rwth.idsg.steve.repository.dto.User;
import de.rwth.idsg.steve.repository.dto.UserNotificationFeature;
import de.rwth.idsg.steve.web.dto.UserForm;
import de.rwth.idsg.steve.web.dto.UserQueryForm;
import jooq.steve.db.tables.records.AddressRecord;
Expand All @@ -31,7 +32,7 @@
import org.jooq.Field;
import org.jooq.JoinType;
import org.jooq.Record1;
import org.jooq.Record7;
import org.jooq.Record8;
import org.jooq.Result;
import org.jooq.SelectConditionStep;
import org.jooq.SelectQuery;
Expand Down Expand Up @@ -68,6 +69,7 @@ public List<User.Overview> getOverview(UserQueryForm form) {
.name(r.value4() + " " + r.value5())
.phone(r.value6())
.email(r.value7())
.enabledFeatures(UserNotificationFeature.splitFeatures(r.value8()))
.build()
);
}
Expand Down Expand Up @@ -116,6 +118,42 @@ public User.Details getDetails(int userPk) {
.build();
}

@Override
public User.Details getDetails(String ocppIdTag) {
Integer ocppPk = ctx.select(OCPP_TAG.OCPP_TAG_PK)
.from(OCPP_TAG)
.where(OCPP_TAG.ID_TAG.eq(ocppIdTag))
.fetchOne(OCPP_TAG.OCPP_TAG_PK);

if (ocppPk == null) {
throw new SteveException("There is no OCPP_Tag: '%s'", ocppIdTag);
}

// -------------------------------------------------------------------------
// 1. user table
// -------------------------------------------------------------------------

UserRecord ur = ctx.selectFrom(USER)
.where(USER.OCPP_TAG_PK.equal(ocppPk))
.fetchOne();

if (ur == null) {
throw new SteveException("There is no user with OCPP_TAG '%s'", ocppIdTag);
}

// -------------------------------------------------------------------------
// 2. address table
// -------------------------------------------------------------------------

AddressRecord ar = addressRepository.get(ctx, ur.getAddressPk());

return User.Details.builder()
.userRecord(ur)
.address(ar)
.ocppIdTag(Optional.ofNullable(ocppIdTag))
.build();
}

@Override
public void add(UserForm form) {
ctx.transaction(configuration -> {
Expand Down Expand Up @@ -163,7 +201,9 @@ public void delete(int userPk) {
// -------------------------------------------------------------------------

@SuppressWarnings("unchecked")
private Result<Record7<Integer, Integer, String, String, String, String, String>> getOverviewInternal(UserQueryForm form) {
private Result<Record8<Integer, Integer, String, String, String, String, String, String>>
getOverviewInternal(UserQueryForm form) {

SelectQuery selectQuery = ctx.selectQuery();
selectQuery.addFrom(USER);
selectQuery.addJoin(OCPP_TAG, JoinType.LEFT_OUTER_JOIN, USER.OCPP_TAG_PK.eq(OCPP_TAG.OCPP_TAG_PK));
Expand All @@ -174,7 +214,8 @@ private Result<Record7<Integer, Integer, String, String, String, String, String>
USER.FIRST_NAME,
USER.LAST_NAME,
USER.PHONE,
USER.E_MAIL
USER.E_MAIL,
USER.USER_NOTIFICATION_FEATURES
);

if (form.isSetUserPk()) {
Expand Down Expand Up @@ -225,6 +266,8 @@ private void addInternal(DSLContext ctx, UserForm form, Integer addressPk) {
.set(USER.NOTE, form.getNote())
.set(USER.ADDRESS_PK, addressPk)
.set(USER.OCPP_TAG_PK, selectOcppTagPk(form.getOcppIdTag()))
.set(USER.USER_NOTIFICATION_FEATURES,
UserNotificationFeature.joinFeatures(form.getEnabledFeatures()))
.execute();

if (count != 1) {
Expand All @@ -243,6 +286,7 @@ private void updateInternal(DSLContext ctx, UserForm form, Integer addressPk) {
.set(USER.NOTE, form.getNote())
.set(USER.ADDRESS_PK, addressPk)
.set(USER.OCPP_TAG_PK, selectOcppTagPk(form.getOcppIdTag()))
.set(USER.USER_NOTIFICATION_FEATURES, UserNotificationFeature.joinFeatures(form.getEnabledFeatures()))
.where(USER.USER_PK.eq(form.getUserPk()))
.execute();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import de.rwth.idsg.steve.repository.dto.UpdateTransactionParams;
import de.rwth.idsg.steve.service.notification.OccpStationBooted;
import de.rwth.idsg.steve.service.notification.OcppStationStatusFailure;
import de.rwth.idsg.steve.service.notification.OcppStationStatusSuspendedEV;
import de.rwth.idsg.steve.service.notification.OcppTransactionEnded;
import de.rwth.idsg.steve.service.notification.OcppTransactionStarted;
import jooq.steve.db.enums.TransactionStopEventActor;
Expand Down Expand Up @@ -147,6 +148,11 @@ public StatusNotificationResponse statusNotification(
chargeBoxIdentity, parameters.getConnectorId(), parameters.getErrorCode().value()));
}

if (parameters.getStatus() == ChargePointStatus.SUSPENDED_EV) {
applicationEventPublisher.publishEvent(new OcppStationStatusSuspendedEV(
chargeBoxIdentity, parameters.getConnectorId(), parameters.getTimestamp()));
}

return new StatusNotificationResponse();
}

Expand Down
42 changes: 35 additions & 7 deletions src/main/java/de/rwth/idsg/steve/service/MailService.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import static de.rwth.idsg.steve.utils.StringUtils.splitByComma;
import static de.rwth.idsg.steve.utils.StringUtils.isValidAddress;
import java.util.List;

/**
* @author Sevket Goekay <[email protected]>
Expand Down Expand Up @@ -81,7 +84,7 @@ public MailSettings getSettings() {

public void sendTestMail() {
try {
send("Test", "Test");
send("Test", "Test", "");
} catch (MessagingException e) {
throw new SteveException("Failed to send mail", e);
}
Expand All @@ -90,29 +93,54 @@ public void sendTestMail() {
public void sendAsync(String subject, String body) {
executorService.execute(() -> {
try {
send(subject, body);
send(subject, body, "");
} catch (MessagingException e) {
log.error("Failed to send mail", e);
}
});
}

public void send(String subject, String body) throws MessagingException {
MailSettings settings = getSettings();
public void sendAsync(String subject, String body, String recipientAddresses) {
executorService.execute(() -> {
try {
send(subject, body, recipientAddresses);
} catch (MessagingException e) {
log.error("Failed to send mail", e);
}
});
}

private void send(String subject, String body, String recipientAddresses) throws MessagingException {
MailSettings settingsLocal = getSettings();

Message mail = new MimeMessage(session);
mail.setSubject("[SteVe] " + subject);
mail.setContent(body, "text/plain");
mail.setFrom(new InternetAddress(settings.getFrom()));
mail.setFrom(new InternetAddress(settingsLocal.getFrom()));

List<String> eMailAddresses;

for (String rep : settings.getRecipients()) {
mail.addRecipient(Message.RecipientType.TO, new InternetAddress(rep));
if (recipientAddresses.isEmpty()) {
eMailAddresses = settingsLocal.getRecipients();
} else {
eMailAddresses = splitByComma(recipientAddresses);
}

for (String rep : eMailAddresses) {
if (isValidAddress(rep)) {
mail.addRecipient(Message.RecipientType.TO, new InternetAddress(rep));
} else {
log.error("Failed to send mail to " + rep + "! Format of the address is invalid.");
}
}

try (Transport transport = session.getTransport()) {
transport.connect();
transport.sendMessage(mail, mail.getAllRecipients());
}
catch (Exception e) {
log.error("Failed to send mail(s)! ", e);
}
}

// -------------------------------------------------------------------------
Expand Down
Loading