Skip to content

Commit

Permalink
Send out additional emails
Browse files Browse the repository at this point in the history
Fixes #253
  • Loading branch information
1-alex98 committed Sep 11, 2018
1 parent d9f737d commit ebb9a8c
Show file tree
Hide file tree
Showing 16 changed files with 310 additions and 33 deletions.
14 changes: 13 additions & 1 deletion 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 @@ -46,9 +50,11 @@ public class BanInfoTest extends AbstractIntegrationTest {
}
}
*/
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("[email protected]"),
ArgumentMatchers.eq("[email protected]"),
ArgumentMatchers.eq("[email protected]"),
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[.]")
);
}
}
45 changes: 45 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,45 @@
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.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\"}}}}}";

@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', '[email protected]', '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', '[email protected]', '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},\n your username changed to {1}}
mail-subject: ${USERNAME_CHANGE_EMAIL_SUBJECT:Username changed}
ban:
ban-mail-body: ${BAN_EMAIL_BODY:Hello {0},\nYour account was banned\nReason - {1}\nBanner - {2}\nTime - {3}\nType - {4}\nExpires - {5}.\nThank you for your fairness and acceptance.}
ban-mail-subject: ${BAN_EMAIL_SUBJECT:ban subject}
ban-revoke-mail-body: ${BAN_REVOKE_EMAIL_BODY:revoke email body}
ban-revoke-mail-subject: ${BAN_REVOKE_EMAIL_SUBJECT:Hello {0},\nYour account was been unbanned.\nModerator that unbanned you - {1}\nReason - {2}\nOriginal reason of the ban - {3}\noriginal banner - {4}\nTime of original ban - {5}.\nThank you for your fairness and acceptance.}

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

0 comments on commit ebb9a8c

Please sign in to comment.