[AB-xxx] fixed send message action sending for every level change

This commit is contained in:
Sheldan
2024-07-31 00:11:57 +02:00
parent 5b5e4973a7
commit 99bf9a9be0
12 changed files with 201 additions and 25 deletions

View File

@@ -48,7 +48,7 @@ public class AddMemberToChannelLevelAction implements LevelActionListener {
}
@Override
public boolean shouldExecute(AUserExperience aUserExperience, LevelAction levelAction) {
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
}

View File

@@ -48,7 +48,7 @@ public class AddRoleLevelAction implements LevelActionListener {
}
@Override
public boolean shouldExecute(AUserExperience aUserExperience, LevelAction levelAction) {
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
}

View File

@@ -48,7 +48,7 @@ public class RemoveMemberFromChannelLevelAction implements LevelActionListener {
}
@Override
public boolean shouldExecute(AUserExperience aUserExperience, LevelAction levelAction) {
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
}

View File

@@ -49,7 +49,7 @@ public class RemoveRoleLevelAction implements LevelActionListener {
}
@Override
public boolean shouldExecute(AUserExperience aUserExperience, LevelAction levelAction) {
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
}

View File

@@ -73,8 +73,15 @@ public class SendMessageToChannelLevelAction implements LevelActionListener {
}
@Override
public boolean shouldExecute(AUserExperience aUserExperience, LevelAction levelAction) {
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
if(!oldLevel.equals(aUserExperience.getLevelOrDefault())) { // this means the user changed level now, this is the path from gaining a lot of experience
boolean jumpedLevelToMatch = oldLevel < levelAction.getLevel().getLevel() && aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
// this boolean means that the user did NOT have the action earlier, but does now (and more than that)
return jumpedLevelToMatch || aUserExperience.getLevelOrDefault().equals(levelAction.getLevel().getLevel()); // or the user matches the level _exactly_, this is the path from normally gaining experience
} else {
// This case is useful for re-joining, because this means, that the user did _not_ change level, and already is somewhere way above
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
}
}
@Override

View File

@@ -337,8 +337,8 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
.builder()
.build();
boolean userChangesLevel = !Objects.equals(newLevel.getLevel(), aUserExperience.getCurrentLevel().getLevel());
Integer oldLevel = aUserExperience.getCurrentLevel() != null ? aUserExperience.getCurrentLevel().getLevel() : 0;
if(userChangesLevel) {
Integer oldLevel = aUserExperience.getCurrentLevel() != null ? aUserExperience.getCurrentLevel().getLevel() : 0;
log.info("User {} in server {} changed level. New {}, Old {}.", member.getIdLong(),
member.getGuild().getIdLong(), newLevel.getLevel(),
oldLevel);
@@ -373,7 +373,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
}
aUserExperience.setMessageCount(aUserExperience.getMessageCount() + 1L);
if(userChangesLevel && featureModeService.featureModeActive(ExperienceFeatureDefinition.EXPERIENCE, server, ExperienceFeatureMode.LEVEL_ACTION)) {
levelActionService.applyLevelActionsToUser(aUserExperience)
levelActionService.applyLevelActionsToUser(aUserExperience, oldLevel)
.thenAccept(unused -> {
log.info("Executed level actions for user {}.", userInServerId);
})

View File

@@ -49,6 +49,11 @@ public class LevelActionServiceBean implements LevelActionService {
@Override
public CompletableFuture<Void> applyLevelActionsToUser(AUserExperience user) {
return applyLevelActionsToUser(user, user.getLevelOrDefault());
}
@Override
public CompletableFuture<Void> applyLevelActionsToUser(AUserExperience user, Integer oldLevel) {
if(levelActions == null || levelActions.isEmpty()) {
return CompletableFuture.completedFuture(null);
}
@@ -60,8 +65,16 @@ public class LevelActionServiceBean implements LevelActionService {
Map<Integer, List<LevelAction>> actionConfigMap = new HashMap<>();
Map<String, LevelActionListener> actionStringListenerMap = levelActions
.stream()
.collect(Collectors.toMap(a -> a.getName().toLowerCase(), Function.identity()));
levelActionsOfUserInServer.forEach(levelAction -> {
if(levelAction.getLevel().getLevel() > user.getLevelOrDefault()) {
LevelActionListener listener = actionStringListenerMap.get(levelAction.getAction());
if(listener == null) { // if for some reason the config is still in the database, but we don't have code for it anymore
return;
}
if(!listener.shouldExecute(user, oldLevel, levelAction)) {
return;
}
if(actionConfigMap.containsKey(levelAction.getLevel().getLevel())) {
@@ -73,9 +86,6 @@ public class LevelActionServiceBean implements LevelActionService {
}
});
Map<String, LevelActionListener> actionStringListenerMap = levelActions
.stream()
.collect(Collectors.toMap(a -> a.getName().toLowerCase(), Function.identity()));
List<Integer> levels = actionConfigMap
.keySet()

View File

@@ -0,0 +1,84 @@
package dev.sheldan.abstracto.experience.listener;
import dev.sheldan.abstracto.experience.model.database.AExperienceLevel;
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
import dev.sheldan.abstracto.experience.model.database.LevelAction;
import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class AddRoleLevelActionTest {
@InjectMocks
private AddRoleLevelAction action;
@Mock
private AUserExperience exp;
@Mock
private LevelAction levelAction;
@Mock
private AExperienceLevel level;
private final Integer LOW_LEVEL = 1;
private final Integer MID_LEVEL = 2;
private final Integer HIGH_LEVEL = 3;
@Before
public void setup() {
when(levelAction.getLevel()).thenReturn(level);
}
@Test // rejoin too low case
public void noLevelChangeActionNotReached() {
executeTest(LOW_LEVEL, LOW_LEVEL, HIGH_LEVEL, false);
}
@Test // re-join exact case
public void noLevelChangeActionReached() {
executeTest(LOW_LEVEL, LOW_LEVEL, LOW_LEVEL, true);
}
@Test // normal leveling, higher action
public void levelChangeActionNotReached() {
executeTest(LOW_LEVEL, MID_LEVEL, HIGH_LEVEL, false);
}
@Test // normal leveling
public void levelChangeActionReached() {
executeTest(LOW_LEVEL, MID_LEVEL, MID_LEVEL, true);
}
@Test // a case for this is a large experience jump
public void levelChangeActionOverJumped() {
executeTest(LOW_LEVEL, HIGH_LEVEL, MID_LEVEL, true);
}
@Test // a case for this is a re-join
public void noLevelChangeActionOverJumped() {
executeTest(HIGH_LEVEL, HIGH_LEVEL, LOW_LEVEL, true);
}
@Test // we dont want to re-execute previous actions (previous = lower level)
public void levelChangeActionEqualsPrevious() {
executeTest(LOW_LEVEL, MID_LEVEL, LOW_LEVEL, true);
}
@Test // we dont want to re-execute previous actions (previous = way lower level)
public void levelChangeActionBelow() {
executeTest(MID_LEVEL, HIGH_LEVEL, LOW_LEVEL, true);
}
private void executeTest(Integer oldLevel, Integer currentLevel, Integer actionLevel, boolean expected) {
when(exp.getLevelOrDefault()).thenReturn(currentLevel);
when(level.getLevel()).thenReturn(actionLevel);
Assertions.assertThat(action.shouldExecute(exp, oldLevel, levelAction)).isEqualTo(expected);
}
}

View File

@@ -0,0 +1,86 @@
package dev.sheldan.abstracto.experience.listener;
import dev.sheldan.abstracto.experience.model.database.AExperienceLevel;
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
import dev.sheldan.abstracto.experience.model.database.LevelAction;
import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class RemoveMemberFromChannelLevelActionTest {
@InjectMocks
private SendMessageToChannelLevelAction action;
@Mock
private AUserExperience exp;
@Mock
private LevelAction levelAction;
@Mock
private AExperienceLevel level;
private final Integer LOW_LEVEL = 1;
private final Integer MID_LEVEL = 2;
private final Integer HIGH_LEVEL = 3;
@Before
public void setup() {
when(levelAction.getLevel()).thenReturn(level);
}
@Test // rejoin too low case
public void noLevelChangeActionNotReached() {
executeTest(LOW_LEVEL, LOW_LEVEL, HIGH_LEVEL, false);
}
@Test // re-join exact case
public void noLevelChangeActionReached() {
executeTest(LOW_LEVEL, LOW_LEVEL, LOW_LEVEL, true);
}
@Test // normal leveling, higher action
public void levelChangeActionNotReached() {
executeTest(LOW_LEVEL, MID_LEVEL, HIGH_LEVEL, false);
}
@Test // normal leveling
public void levelChangeActionReached() {
executeTest(LOW_LEVEL, MID_LEVEL, MID_LEVEL, true);
}
@Test // a case for this is a large experience jump
public void levelChangeActionOverJumped() {
executeTest(LOW_LEVEL, HIGH_LEVEL, MID_LEVEL, true);
}
@Test // a case for this is a re-join
public void noLevelChangeActionOverJumped() {
executeTest(HIGH_LEVEL, HIGH_LEVEL, LOW_LEVEL, true);
}
@Test // we dont want to re-execute previous actions (previous = lower level)
public void levelChangeActionEqualsPrevious() {
executeTest(LOW_LEVEL, MID_LEVEL, LOW_LEVEL, false);
}
@Test // we dont want to re-execute previous actions (previous = way lower level)
public void levelChangeActionBelow() {
executeTest(MID_LEVEL, HIGH_LEVEL, LOW_LEVEL, false);
}
private void executeTest(Integer oldLevel, Integer currentLevel, Integer actionLevel, boolean expected) {
when(exp.getLevelOrDefault()).thenReturn(currentLevel);
when(level.getLevel()).thenReturn(actionLevel);
Assertions.assertThat(action.shouldExecute(exp, oldLevel, levelAction)).isEqualTo(expected);
}
}

View File

@@ -10,7 +10,7 @@ public interface LevelActionListener {
void apply(AUserExperience userExperience, LevelAction levelAction, MemberActionModification container);
boolean shouldExecute(AUserExperience aUserExperience, LevelAction levelAction);
boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction);
void prepareAction(LevelAction levelAction);

View File

@@ -12,6 +12,7 @@ import java.util.concurrent.CompletableFuture;
public interface LevelActionService {
CompletableFuture<Void> applyLevelActionsToUser(AUserExperience user);
CompletableFuture<Void> applyLevelActionsToUser(AUserExperience user, Integer oldLevel);
List<String> getAvailableLevelActions();
Optional<LevelActionListener> getLevelActionListenerForName(String name);