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

Send out additional emails #261

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 14 additions & 2 deletions src/inttest/java/com/faforever/api/data/BanInfoTest.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.faforever.api.data;

import com.faforever.api.AbstractIntegrationTest;
import com.faforever.api.email.EmailSender;
import com.faforever.api.player.PlayerRepository;
import org.junit.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.Sql.ExecutionPhase;
Expand Down Expand Up @@ -39,16 +43,18 @@ public class BanInfoTest extends AbstractIntegrationTest {
"player": {
"data": {
"type": "player",
"id": "3"
"id": "2"
}
}
}
}
}
*/
private static final String testPost = "{\"data\":{\"type\":\"banInfo\",\"attributes\":{\"level\":\"CHAT\",\"reason\":\"This test ban should be revoked\"},\"relationships\":{\"author\":{\"data\":{\"type\":\"player\",\"id\":\"1\"}},\"player\":{\"data\":{\"type\":\"player\",\"id\":\"3\"}}}}}";
private static final String testPost = "{\"data\":{\"type\":\"banInfo\",\"attributes\":{\"level\":\"CHAT\",\"reason\":\"This test ban should be revoked\"},\"relationships\":{\"author\":{\"data\":{\"type\":\"player\",\"id\":\"2\"}},\"player\":{\"data\":{\"type\":\"player\",\"id\":\"3\"}}}}}";
@Autowired
PlayerRepository playerRepository;
@MockBean
private EmailSender emailSender;

@Test
@WithUserDetails(AUTH_USER)
Expand Down Expand Up @@ -98,5 +104,11 @@ public void canCreateBanInfoAsModerator() throws Exception {
.andExpect(status().isCreated());

assertThat(playerRepository.getOne(3).getBans().size(), is(1));
Mockito.verify(emailSender).sendMail(ArgumentMatchers.eq("integration-test@faforever.com"),
ArgumentMatchers.eq("integration-test@faforever.com"),
ArgumentMatchers.eq("admin@faforever.com"),
ArgumentMatchers.eq("ban subject"),
ArgumentMatchers.matches("Hello ADMIN,\\|Your account was banned\\|Reason - This test ban should be revoked\\|Banner - MODERATOR\\|Time - (.)*\\|Type - CHAT\\|Expires - never\\|Thank you for your fairness and acceptance[.]")
);
}
}
47 changes: 47 additions & 0 deletions src/inttest/java/com/faforever/api/data/BanRevokeElideTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.faforever.api.data;

import com.faforever.api.AbstractIntegrationTest;
import com.faforever.api.data.domain.BanStatus;
import com.faforever.api.email.EmailSender;
import com.faforever.api.player.PlayerRepository;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.Sql.ExecutionPhase;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:sql/prepDefaultUser.sql")
@Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:sql/prepBanRevokeData.sql")
@Sql(executionPhase = ExecutionPhase.AFTER_TEST_METHOD, scripts = "classpath:sql/cleanBanRevokeData.sql")
public class BanRevokeElideTest extends AbstractIntegrationTest {
@MockBean
private EmailSender emailSender;
@Autowired
private PlayerRepository playerRepository;
/*
{"data":{"type":"banRevokeData","attributes":{"reason":"unban"},"relationships":{"ban":{"data":{"type":"banInfo","id":"1"}},"author":{"data":{"type":"player","id":"2"}}}}} */
private static final String TEST_REVOKE="{\"data\":{\"type\":\"banRevokeData\",\"attributes\":{\"reason\":\"unban\"},\"relationships\":{\"ban\":{\"data\":{\"type\":\"banInfo\",\"id\":\"1\"}},\"author\":{\"data\":{\"type\":\"player\",\"id\":\"2\"}}}}}";

@Ignore(value = "Posting of ban revokes never worked, moderator use to change expire date instead see issue #259")
@WithUserDetails(AUTH_MODERATOR)
@Test
public void testRevokeBanWithId1() throws Exception {
assertThat(playerRepository.getOne(4).getBans().size(), is(1));
assertThat(playerRepository.getOne(4).getBans().iterator().next().getBanStatus(), is(BanStatus.BANNED));

mockMvc.perform(post("/data/banRevokeData")
.content(TEST_REVOKE))
.andExpect(status().isCreated());

assertThat(playerRepository.getOne(4).getBans().iterator().next().getBanStatus(), is(BanStatus.DISABLED));
Mockito.verify(emailSender).sendMail("","","","","");
}
}
8 changes: 8 additions & 0 deletions src/inttest/resources/config/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ faf-api:
mautic:
client-id: banana
client-secret: banana
username-change:
mail-body: ${USERNAME_CHANGE_EMAIL_BODY:Hello {0},| your username changed to {1}}
mail-subject: ${USERNAME_CHANGE_EMAIL_SUBJECT:Username changed}
ban:
ban-mail-body: ${BAN_EMAIL_BODY:Hello {0},|Your account was banned|Reason - {1}|Banner - {2}|Time - {3}|Type - {4}|Expires - {5}|Thank you for your fairness and acceptance.}
ban-mail-subject: ${BAN_EMAIL_SUBJECT:ban subject}
ban-revoke-mail-body: ${BAN_REVOKE_EMAIL_BODY:Hello {0},|Your account was been unbanned.|Moderator that unbanned you - {1}|Reason - {2}|Original reason of the ban - {3}|original banner - {4}|Time of original ban - {5}.|Thank you for your fairness and acceptance.}
ban-revoke-mail-subject: ${BAN_REVOKE_EMAIL_SUBJECT:email ban revoke subject}


logging:
Expand Down
2 changes: 2 additions & 0 deletions src/inttest/resources/sql/cleanBanRevokeData.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DELETE FROM ban_revoke;
DELETE FROM ban;
6 changes: 3 additions & 3 deletions src/inttest/resources/sql/prepBanData.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ INSERT INTO login (id, login, email, password) VALUES
(4, 'BANNED', 'banned@faforever.com', 'not relevant');

INSERT INTO ban (id, player_id, author_id, reason, expires_at, level) VALUES
(1, 4, 1, 'Test permaban', DATE_ADD(NOW(), INTERVAL 1 DAY), 'GLOBAL'),
(2, 2, 1, 'To be revoked ban', DATE_ADD(NOW(), INTERVAL 1 DAY), 'GLOBAL');
(1, 4, 2, 'Test permaban', DATE_ADD(NOW(), INTERVAL 1 DAY), 'GLOBAL'),
(2, 2, 2, 'To be revoked ban', DATE_ADD(NOW(), INTERVAL 1 DAY), 'GLOBAL');

INSERT INTO ban_revoke (ban_id, reason, author_id) VALUES
(2, 'Test revoke', 1);
(2, 'Test revoke', 2);

8 changes: 8 additions & 0 deletions src/inttest/resources/sql/prepBanRevokeData.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
DELETE FROM ban_revoke;
DELETE FROM ban;

INSERT INTO login (id, login, email, password) VALUES
(4, 'BANNED', 'banned@faforever.com', 'not relevant');

INSERT INTO ban (id, player_id, author_id, reason, expires_at, level) VALUES
(1, 4, 2, 'Test permaban', DATE_ADD(NOW(), INTERVAL 1 DAY), 'GLOBAL');
16 changes: 16 additions & 0 deletions src/main/java/com/faforever/api/config/FafApiProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public class FafApiProperties {
private Anope anope = new Anope();
private Rating rating = new Rating();
private Tutorial tutorial = new Tutorial();
private UsernameChange usernameChange = new UsernameChange();
private Ban ban = new Ban();

@Data
public static class OAuth2 {
Expand Down Expand Up @@ -250,4 +252,18 @@ public class Rating {
public static class Tutorial {
private String thumbnailUrlFormat;
}

@Data
public class UsernameChange {
private String mailBody;
private String mailSubject;
}

@Data
public class Ban {
private String banMailBody;
private String banMailSubject;
private String banRevokeMailBody;
private String banRevokeMailSubject;
}
}
13 changes: 11 additions & 2 deletions src/main/java/com/faforever/api/config/elide/ElideConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@
import com.faforever.api.data.checks.permission.HasBanUpdate;
import com.faforever.api.data.checks.permission.HasLadder1v1Update;
import com.faforever.api.data.checks.permission.IsModerator;
import com.faforever.api.data.domain.BanInfo;
import com.faforever.api.data.domain.BanRevokeData;
import com.faforever.api.data.listeners.BanInfoPostCreateListener;
import com.faforever.api.data.listeners.BanRevokePostCreateListener;
import com.faforever.api.security.ExtendedAuditLogger;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yahoo.elide.Elide;
import com.yahoo.elide.ElideSettingsBuilder;
import com.yahoo.elide.annotation.OnCreatePostCommit;
import com.yahoo.elide.core.EntityDictionary;
import com.yahoo.elide.core.filter.dialect.RSQLFilterDialect;
import com.yahoo.elide.jsonapi.JsonApiMapper;
Expand All @@ -37,18 +42,22 @@ public class ElideConfig {
public static final String DEFAULT_CACHE_NAME = "Elide.defaultCache";

@Bean
public Elide elide(SpringHibernateDataStore springHibernateDataStore, ObjectMapper objectMapper, EntityDictionary entityDictionary, ExtendedAuditLogger extendedAuditLogger) {
public Elide elide(SpringHibernateDataStore springHibernateDataStore, ObjectMapper objectMapper, EntityDictionary entityDictionary,
ExtendedAuditLogger extendedAuditLogger, BanInfoPostCreateListener banInfoPostCreateListener, BanRevokePostCreateListener banRevokePostCreateListener) {
RSQLFilterDialect rsqlFilterDialect = new RSQLFilterDialect(entityDictionary);

registerAdditionalConverters();

return new Elide(new ElideSettingsBuilder(springHibernateDataStore)
Elide elide = new Elide(new ElideSettingsBuilder(springHibernateDataStore)
.withJsonApiMapper(new JsonApiMapper(entityDictionary, objectMapper))
.withAuditLogger(extendedAuditLogger)
.withEntityDictionary(entityDictionary)
.withJoinFilterDialect(rsqlFilterDialect)
.withSubqueryFilterDialect(rsqlFilterDialect)
.build());
entityDictionary.bindTrigger(BanInfo.class, OnCreatePostCommit.class, banInfoPostCreateListener);
entityDictionary.bindTrigger(BanRevokeData.class, OnCreatePostCommit.class, banRevokePostCreateListener);
return elide;
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.faforever.api.data.listeners;

import com.faforever.api.data.domain.BanDurationType;
import com.faforever.api.data.domain.BanInfo;
import com.faforever.api.data.domain.Player;
import com.faforever.api.email.EmailService;
import com.yahoo.elide.functions.LifeCycleHook;
import com.yahoo.elide.security.RequestScope;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Optional;

@Component
@Slf4j
public class BanInfoPostCreateListener implements LifeCycleHook<BanInfo> {

private final EmailService emailService;

@Inject
public BanInfoPostCreateListener(EmailService emailService) {
this.emailService = emailService;
}

@Override
public void execute(BanInfo elideEntity, RequestScope requestScope, Optional changes) {
try {
@NotNull Player player = elideEntity.getPlayer();
emailService.sendBanMail(player.getEmail(),
player.getLogin(),
elideEntity.getReason(),
elideEntity.getAuthor().getLogin(),
OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME),
elideEntity.getLevel().name(),
elideEntity.getDuration() == BanDurationType.PERMANENT ? "never" : elideEntity.getExpiresAt().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
} catch (Exception e) {
log.error("Sending ban email failed", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.faforever.api.data.listeners;

import com.faforever.api.data.domain.BanInfo;
import com.faforever.api.data.domain.BanRevokeData;
import com.faforever.api.data.domain.Player;
import com.faforever.api.email.EmailService;
import com.yahoo.elide.functions.LifeCycleHook;
import com.yahoo.elide.security.ChangeSpec;
import com.yahoo.elide.security.RequestScope;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.time.format.DateTimeFormatter;
import java.util.Optional;

@Slf4j
@Component
public class BanRevokePostCreateListener implements LifeCycleHook<BanRevokeData> {
private final EmailService emailService;

public BanRevokePostCreateListener(EmailService emailService) {
this.emailService = emailService;
}

@Override
public void execute(BanRevokeData banRevoke, RequestScope requestScope, Optional<ChangeSpec> changes) {
try {
@NotNull BanInfo ban = banRevoke.getBan();
@NotNull Player player = ban.getPlayer();
emailService.sendBanRevokeMail(player.getEmail(),
player.getLogin(),
banRevoke.getAuthor().getLogin(),
banRevoke.getReason(),
ban.getReason(),
ban.getAuthor().getLogin(),
ban.getCreateTime().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
} catch (Exception e) {
log.error("Failed to send ban revoke email", e);
}
}
}
39 changes: 39 additions & 0 deletions src/main/java/com/faforever/api/email/EmailService.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.faforever.api.email;

import com.faforever.api.config.FafApiProperties;
import com.faforever.api.config.FafApiProperties.Ban;
import com.faforever.api.config.FafApiProperties.PasswordReset;
import com.faforever.api.config.FafApiProperties.Registration;
import com.faforever.api.config.FafApiProperties.UsernameChange;
import com.faforever.api.error.ApiException;
import com.faforever.api.error.Error;
import com.faforever.api.error.ErrorCode;
Expand Down Expand Up @@ -53,6 +55,43 @@ public void sendActivationMail(String username, String email, String activationU
);
}

@SneakyThrows
public void sendUsernameChangeMail(String email, String oldUsername, String newUsername) {
UsernameChange usernameChange = properties.getUsernameChange();
emailSender.sendMail(
properties.getMail().getFromEmailAddress(),
properties.getMail().getFromEmailName(),
email,
usernameChange.getMailSubject(),
MessageFormat.format(usernameChange.getMailBody(), oldUsername, newUsername)
);
}


@SneakyThrows
public void sendBanMail(String email, String username, String reason, String banner, String createTime, String type, String expires) {
Ban ban = properties.getBan();
emailSender.sendMail(
properties.getMail().getFromEmailAddress(),
properties.getMail().getFromEmailName(),
email,
ban.getBanMailSubject(),
MessageFormat.format(ban.getBanMailBody(), username, reason, banner, createTime, type, expires)
);
}

@SneakyThrows
public void sendBanRevokeMail(String email, String username, String moderatorThatRevoked, String reasonForRevoke, String reasonForBan, String banner, String banCreateTime) {
Ban ban = properties.getBan();
emailSender.sendMail(
properties.getMail().getFromEmailAddress(),
properties.getMail().getFromEmailName(),
email,
ban.getBanRevokeMailSubject(),
MessageFormat.format(ban.getBanRevokeMailBody(), username, moderatorThatRevoked, reasonForRevoke, reasonForBan, banner, banCreateTime)
);
}

@SneakyThrows
public void sendPasswordResetMail(String username, String email, String passwordResetUrl) {
PasswordReset passwordReset = properties.getPasswordReset();
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/faforever/api/user/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -190,15 +190,15 @@ public void changeLogin(String newLogin, User user, String ipAddress) {
throw new ApiException(new Error(ErrorCode.USERNAME_RESERVED, newLogin, usernameReservationTimeInMonths));
}
});

String oldLogin = user.getLogin();
log.debug("Changing username for user ''{}'' to ''{}''", user, newLogin);
NameRecord nameRecord = new NameRecord()
.setName(user.getLogin())
.setName(oldLogin)
.setPlayer(playerRepository.getOne(user.getId()));
nameRecordRepository.save(nameRecord);

user.setLogin(newLogin);

emailService.sendUsernameChangeMail(user.getEmail(), oldLogin, newLogin);
createOrUpdateMauticContact(userRepository.save(user), ipAddress);
}

Expand Down
8 changes: 8 additions & 0 deletions src/main/resources/config/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ faf-api:
api-key: ${STEAM_API_KEY:banana}
link-to-steam:
steam-redirect-url-format: ${STEAM_LINK_REDIRECT_URL:http://localhost:8010/users/linkToSteam?token=%s}
username-change:
mail-body: ${USERNAME_CHANGE_EMAIL_BODY:Hello {0},| your username changed to {1}}
mail-subject: ${USERNAME_CHANGE_EMAIL_SUBJECT:Username changed}
ban:
ban-mail-body: ${BAN_EMAIL_BODY:Hello {0},|Your account was banned|Reason - {1}|Banner - {2}|Time - {3}|Type - {4}|Expires - {5}|Thank you for your fairness and acceptance.}
ban-mail-subject: ${BAN_EMAIL_SUBJECT:ban subject}
ban-revoke-mail-body: ${BAN_REVOKE_EMAIL_BODY:Hello {0},|Your account was been unbanned.|Moderator that unbanned you - {1}|Reason - {2}|Original reason of the ban - {3}|original banner - {4}|Time of original ban - {5}.|Thank you for your fairness and acceptance.}
ban-revoke-mail-subject: ${BAN_REVOKE_EMAIL_SUBJECT:email ban revoke subject}

spring:
datasource:
Expand Down
8 changes: 8 additions & 0 deletions src/main/resources/config/application-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ faf-api:
api-key: ${STEAM_API_KEY}
link-to-steam:
steam-redirect-url-format: ${STEAM_LINK_REDIRECT_URL}
username-change:
mail-body: ${USERNAME_CHANGE_EMAIL_BODY}
mail-subject: ${USERNAME_CHANGE_EMAIL_SUBJECT}
ban:
ban-mail-body: ${BAN_EMAIL_BODY}
ban-mail-subject: ${BAN_EMAIL_SUBJECT}
ban-revoke-mail-body: ${BAN_REVOKE_EMAIL_BODY}
ban-revoke-mail-subject: ${BAN_REVOKE_EMAIL_SUBJECT}

spring:
datasource:
Expand Down
Loading