Skip to content

Commit 3c3dbde

Browse files
CitralFloRollczivLuckyyy
authored
GH-1147 Save User entity to database (#1147)
* Add database for users, add batch fetching, update tests * Codestyle fixes * Resolve gemini review * Resolve @sadcenter and @Jakubk15 reviews * wip * wip2 * wip * Update methods and failsafe for cache * Refactor `UserManager` and related classes to improve database integration, remove unused methods, and streamline cache handling. * Remove MySQL and Testcontainers integration, refactor database configuration, and streamline ORM functionality. * CR * Remove `created` and `lastLogin` fields from `User`, cleanup related methods, and simplify `UserManager` logic. * Remove `IntegrationTestSpec` and `TestScheduler` utilities as they are no longer used. * Add `lastSeen` and `accountCreated` fields to `User`, enhance `UserManager` logic, introduce date formatting utility, and update WHOIS command and messages accordingly. * Update `UserTable` to use `DATE_STRING` for `lastSeen` and `accountCreated` fields instead of `SERIALIZABLE` * Update `UserTable` to replace `Instant` with `Date` fields and downgrade Minecraft version in `runServer` task --------- Co-authored-by: Rollczi <[email protected]> Co-authored-by: Martin Sulikowski <[email protected]>
1 parent 41ae80a commit 3c3dbde

23 files changed

+429
-450
lines changed

eternalcore-core/src/main/java/com/eternalcode/core/configuration/implementation/PluginConfiguration.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import com.eternalcode.core.configuration.AbstractConfigurationFile;
44
import com.eternalcode.core.database.DatabaseConfig;
55
import com.eternalcode.core.database.DatabaseSettings;
6+
import com.eternalcode.core.util.date.DateConfig;
7+
import com.eternalcode.core.util.date.DateSettings;
68
import com.eternalcode.core.feature.afk.AfkConfig;
79
import com.eternalcode.core.feature.afk.AfkSettings;
810
import com.eternalcode.core.feature.automessage.AutoMessageConfig;
@@ -54,19 +56,20 @@
5456
import eu.okaeri.configs.OkaeriConfig;
5557
import eu.okaeri.configs.annotation.Comment;
5658
import eu.okaeri.configs.annotation.Header;
59+
5760
import java.io.File;
5861

5962
@Header({
60-
"#",
61-
"# This is the main configuration file for EternalCore.",
62-
"#",
63-
"# If you need help with the configuration or have any questions related to EternalCore, join our discord, or create an issue on our GitHub.",
64-
"#",
65-
"# Issues: https://github.com/EternalCodeTeam/EternalCore/issues",
66-
"# Discord: https://discord.gg/FQ7jmGBd6c",
67-
"# Website: https://eternalcode.pl/",
68-
"# Source Code: https://github.com/EternalCodeTeam/EternalCore",
69-
"#",
63+
"#",
64+
"# This is the main configuration file for EternalCore.",
65+
"#",
66+
"# If you need help with the configuration or have any questions related to EternalCore, join our discord, or create an issue on our GitHub.",
67+
"#",
68+
"# Issues: https://github.com/EternalCodeTeam/EternalCore/issues",
69+
"# Discord: https://discord.gg/FQ7jmGBd6c",
70+
"# Website: https://eternalcode.pl/",
71+
"# Source Code: https://github.com/EternalCodeTeam/EternalCore",
72+
"#",
7073
})
7174
@ConfigurationFile
7275
public class PluginConfiguration extends AbstractConfigurationFile {
@@ -93,6 +96,12 @@ public class PluginConfiguration extends AbstractConfigurationFile {
9396
@Comment("# Settings responsible for the database connection")
9497
DatabaseConfig database = new DatabaseConfig();
9598

99+
@Bean(proxied = DateSettings.class)
100+
@Comment("")
101+
@Comment("# Date Configuration")
102+
@Comment("# Settings for date formatting")
103+
DateConfig date = new DateConfig();
104+
96105
@Bean(proxied = SpawnJoinSettings.class)
97106
@Comment("")
98107
@Comment("# Spawn & Join Configuration")

eternalcore-core/src/main/java/com/eternalcode/core/feature/afk/AfkKickController.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.eternalcode.core.translation.TranslationManager;
1010
import com.eternalcode.core.user.User;
1111
import com.eternalcode.core.user.UserManager;
12+
import java.util.Optional;
1213
import java.util.UUID;
1314
import net.kyori.adventure.text.Component;
1415
import net.kyori.adventure.text.minimessage.MiniMessage;
@@ -56,7 +57,8 @@ void onAfkSwitch(AfkSwitchEvent event) {
5657
return;
5758
}
5859

59-
User user = this.userManager.getOrCreate(playerUUID, player.getName());
60+
Optional<User> optionalUser = this.userManager.getUser(playerUUID);
61+
User user = optionalUser.get();
6062
Translation translation = this.translationManager.getMessages(user.getUniqueId());
6163

6264
Component component = this.miniMessage.deserialize(translation.afk().afkKickReason());

eternalcore-core/src/main/java/com/eternalcode/core/feature/msg/MsgServiceImpl.java

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
import com.google.common.cache.CacheBuilder;
1414
import java.time.Duration;
1515
import java.util.HashSet;
16-
import java.util.Optional;
1716
import java.util.Set;
1817
import java.util.UUID;
18+
import org.bukkit.Server;
1919
import org.bukkit.entity.Player;
2020

2121
@Service
@@ -27,6 +27,7 @@ class MsgServiceImpl implements MsgService {
2727
private final MsgPresenter presenter;
2828
private final EventCaller eventCaller;
2929
private final MsgToggleService msgToggleService;
30+
private final Server server;
3031

3132
private final Cache<UUID, UUID> replies = CacheBuilder.newBuilder()
3233
.expireAfterWrite(Duration.ofHours(1))
@@ -40,7 +41,7 @@ class MsgServiceImpl implements MsgService {
4041
IgnoreService ignoreService,
4142
UserManager userManager,
4243
EventCaller eventCaller,
43-
MsgToggleService msgToggleService
44+
MsgToggleService msgToggleService, Server server
4445
) {
4546
this.noticeService = noticeService;
4647
this.ignoreService = ignoreService;
@@ -49,15 +50,31 @@ class MsgServiceImpl implements MsgService {
4950
this.msgToggleService = msgToggleService;
5051

5152
this.presenter = new MsgPresenter(noticeService);
53+
this.server = server;
5254
}
5355

54-
void privateMessage(User sender, User target, String message) {
55-
if (target.getClientSettings().isOffline()) {
56+
@Override
57+
public void reply(Player sender, String message) {
58+
UUID uuid = this.replies.getIfPresent(sender.getUniqueId());
59+
60+
if (uuid == null) {
61+
this.noticeService.player(sender.getUniqueId(), translation -> translation.msg().noReply());
62+
63+
return;
64+
}
65+
66+
Player target = this.server.getPlayer(uuid);
67+
if (target == null) {
5668
this.noticeService.player(sender.getUniqueId(), translation -> translation.argument().offlinePlayer());
5769

5870
return;
5971
}
6072

73+
this.sendMessage(sender, target, message);
74+
}
75+
76+
@Override
77+
public void sendMessage(Player sender, Player target, String message) {
6178
UUID uniqueId = target.getUniqueId();
6279

6380
this.msgToggleService.getState(uniqueId).thenAccept(msgState -> {
@@ -75,33 +92,11 @@ void privateMessage(User sender, User target, String message) {
7592

7693
MsgEvent event = new MsgEvent(sender.getUniqueId(), uniqueId, message);
7794
this.eventCaller.callEvent(event);
78-
this.presenter.onMessage(new Message(sender, target, event.getContent(), this.socialSpy, isIgnored));
95+
this.presenter.onMessage(new Message(toUser(sender), toUser(target), event.getContent(), this.socialSpy, isIgnored));
7996
});
8097
});
8198
}
8299

83-
void reply(User sender, String message) {
84-
UUID uuid = this.replies.getIfPresent(sender.getUniqueId());
85-
86-
if (uuid == null) {
87-
this.noticeService.player(sender.getUniqueId(), translation -> translation.msg().noReply());
88-
89-
return;
90-
}
91-
92-
Optional<User> targetOption = this.userManager.getUser(uuid);
93-
94-
if (targetOption.isEmpty()) {
95-
this.noticeService.player(sender.getUniqueId(), translation -> translation.argument().offlinePlayer());
96-
97-
return;
98-
}
99-
100-
User target = targetOption.get();
101-
102-
this.privateMessage(sender, target, message);
103-
}
104-
105100
@Override
106101
public void enableSpy(UUID player) {
107102
this.socialSpy.add(player);
@@ -117,14 +112,9 @@ public boolean isSpy(UUID player) {
117112
return this.socialSpy.contains(player);
118113
}
119114

120-
@Override
121-
public void reply(Player sender, String message) {
122-
this.reply(this.userManager.getOrCreate(sender.getUniqueId(), sender.getName()), message);
115+
private User toUser(Player target) {
116+
return this.userManager.getUser(target.getUniqueId())
117+
.orElseThrow(() -> new IllegalStateException("User not found for player " + target.getName()));
123118
}
124119

125-
@Override
126-
public void sendMessage(Player sender, Player target, String message) {
127-
User user = this.userManager.getOrCreate(target.getUniqueId(), target.getName());
128-
this.privateMessage(this.userManager.getOrCreate(sender.getUniqueId(), sender.getName()), user, message);
129-
}
130120
}

eternalcore-core/src/main/java/com/eternalcode/core/feature/whois/ENWhoIsMessages.java

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,31 @@
99
@Getter
1010
@Accessors(fluent = true)
1111
public class ENWhoIsMessages extends OkaeriConfig implements WhoIsMessages {
12-
12+
1313
@Comment({
14-
" ",
15-
"# {PLAYER} - Player name",
16-
"# {UUID} - Player UUID",
17-
"# {IP} - Player IP",
18-
"# {WALK-SPEED} - Player walk speed",
19-
"# {SPEED} - Player fly speed",
20-
"# {PING} - Player ping",
21-
"# {LEVEL} - Player level",
22-
"# {HEALTH} - Player health",
23-
"# {FOOD} - Player food level"
14+
" ",
15+
"# {PLAYER} - Player name",
16+
"# {UUID} - Player UUID",
17+
"# {IP} - Player IP",
18+
"# {WALK-SPEED} - Player walk speed",
19+
"# {SPEED} - Player fly speed",
20+
"# {PING} - Player ping",
21+
"# {LEVEL} - Player level",
22+
"# {HEALTH} - Player health",
23+
"# {FOOD} - Player food level",
24+
"# {LAST-SEEN} - Player last seen",
25+
"# {ACCOUNT-CREATED} - Player account created"
2426
})
2527
public List<String> info = List.of(
26-
"<color:#9d6eef>► <white>Target name: <color:#9d6eef>{PLAYER}",
27-
"<color:#9d6eef>► <white>Target UUID: <color:#9d6eef>{UUID}",
28-
"<color:#9d6eef>► <white>Target address: <color:#9d6eef>{IP}",
29-
"<color:#9d6eef>► <white>Target walk speed: <color:#9d6eef>{WALK-SPEED}",
30-
"<color:#9d6eef>► <white>Target fly speed: <color:#9d6eef>{SPEED}",
31-
"<color:#9d6eef>► <white>Target ping: <color:#9d6eef>{PING}<white>ms",
32-
"<color:#9d6eef>► <white>Target level: <color:#9d6eef>{LEVEL}",
33-
"<color:#9d6eef>► <white>Target health: <color:#9d6eef>{HEALTH}",
34-
"<color:#9d6eef>► <white>Target food level: <color:#9d6eef>{FOOD}"
35-
);
28+
"<color:#9d6eef>► <white>Target name: <color:#9d6eef>{PLAYER}",
29+
"<color:#9d6eef>► <white>Target UUID: <color:#9d6eef>{UUID}",
30+
"<color:#9d6eef>► <white>Target address: <color:#9d6eef>{IP}",
31+
"<color:#9d6eef>► <white>Target walk speed: <color:#9d6eef>{WALK-SPEED}",
32+
"<color:#9d6eef>► <white>Target fly speed: <color:#9d6eef>{SPEED}",
33+
"<color:#9d6eef>► <white>Target ping: <color:#9d6eef>{PING}<white>ms",
34+
"<color:#9d6eef>► <white>Target level: <color:#9d6eef>{LEVEL}",
35+
"<color:#9d6eef>► <white>Target health: <color:#9d6eef>{HEALTH}",
36+
"<color:#9d6eef>► <white>Target food level: <color:#9d6eef>{FOOD}",
37+
"<color:#9d6eef>► <white>Last seen: <green>{LAST-SEEN}",
38+
"<color:#9d6eef>► <white>Account created: <green>{ACCOUNT-CREATED}");
3639
}

eternalcore-core/src/main/java/com/eternalcode/core/feature/whois/PLWhoIsMessages.java

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,31 @@
99
@Getter
1010
@Accessors(fluent = true)
1111
public class PLWhoIsMessages extends OkaeriConfig implements WhoIsMessages {
12-
12+
1313
@Comment({
14-
" ",
15-
"# {PLAYER} - nazwa gracza",
16-
"# {UUID} - UUID gracza",
17-
"# {IP} - IP gracza",
18-
"# {WALK-SPEED} - prędkość chodzenia gracza",
19-
"# {SPEED} - prędkość latania gracza",
20-
"# {PING} - ping gracza",
21-
"# {LEVEL} - poziom gracza",
22-
"# {HEALTH} - zdrowie gracza",
23-
"# {FOOD} - poziom najedzenia gracza"
14+
" ",
15+
"# {PLAYER} - nazwa gracza",
16+
"# {UUID} - UUID gracza",
17+
"# {IP} - IP gracza",
18+
"# {WALK-SPEED} - prędkość chodzenia gracza",
19+
"# {SPEED} - prędkość latania gracza",
20+
"# {PING} - ping gracza",
21+
"# {LEVEL} - poziom gracza",
22+
"# {HEALTH} - zdrowie gracza",
23+
"# {FOOD} - poziom najedzenia gracza",
24+
"# {LAST-SEEN} - Ostatnio widziany",
25+
"# {ACCOUNT-CREATED} - Data utworzenia konta"
2426
})
2527
public List<String> info = List.of(
26-
"<color:#9d6eef>► <white>Gracz: <color:#9d6eef>{PLAYER}",
27-
"<color:#9d6eef>► <white>UUID: <color:#9d6eef>{UUID}",
28-
"<color:#9d6eef>► <white>IP: <color:#9d6eef>{IP}",
29-
"<color:#9d6eef>► <white>Szybkość chodzenia: <color:#9d6eef>{WALK-SPEED}",
30-
"<color:#9d6eef>► <white>Szybkość latania: <color:#9d6eef>{SPEED}",
31-
"<color:#9d6eef>► <white>Opóźnienie: <color:#9d6eef>{PING}<white>ms",
32-
"<color:#9d6eef>► <white>Poziom: <color:#9d6eef>{LEVEL}",
33-
"<color:#9d6eef>► <white>Zdrowie: <color:#9d6eef>{HEALTH}",
34-
"<color:#9d6eef>► <white>Poziom najedzenia: <color:#9d6eef>{FOOD}"
35-
);
28+
"<color:#9d6eef>► <white>Gracz: <color:#9d6eef>{PLAYER}",
29+
"<color:#9d6eef>► <white>UUID: <color:#9d6eef>{UUID}",
30+
"<color:#9d6eef>► <white>IP: <color:#9d6eef>{IP}",
31+
"<color:#9d6eef>► <white>Szybkość chodzenia: <color:#9d6eef>{WALK-SPEED}",
32+
"<color:#9d6eef>► <white>Szybkość latania: <color:#9d6eef>{SPEED}",
33+
"<color:#9d6eef>► <white>Opóźnienie: <color:#9d6eef>{PING}<white>ms",
34+
"<color:#9d6eef>► <white>Poziom: <color:#9d6eef>{LEVEL}",
35+
"<color:#9d6eef>► <white>Zdrowie: <color:#9d6eef>{HEALTH}",
36+
"<color:#9d6eef>► <white>Poziom najedzenia: <color:#9d6eef>{FOOD}",
37+
"<color:#9d6eef>► <white>Ostatnio widziany: <green>{LAST-SEEN}",
38+
"<color:#9d6eef>► <white>Data utworzenia konta: <green>{ACCOUNT-CREATED}");
3639
}
Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.eternalcode.core.feature.whois;
22

33
import com.eternalcode.annotations.scan.command.DescriptionDocs;
4+
import com.eternalcode.core.util.date.DateFormatter;
45
import com.eternalcode.core.injector.annotations.Inject;
56
import com.eternalcode.core.notice.NoticeService;
7+
import com.eternalcode.core.user.UserManager;
68
import com.eternalcode.core.viewer.Viewer;
79
import dev.rollczi.litecommands.annotations.argument.Arg;
810
import dev.rollczi.litecommands.annotations.command.Command;
@@ -16,27 +18,34 @@
1618
class WhoIsCommand {
1719

1820
private final NoticeService noticeService;
21+
private final UserManager userManager;
22+
private final DateFormatter dateFormatter;
1923

2024
@Inject
21-
WhoIsCommand(NoticeService noticeService) {
25+
WhoIsCommand(NoticeService noticeService, UserManager userManager, DateFormatter dateFormatter) {
2226
this.noticeService = noticeService;
27+
this.userManager = userManager;
28+
this.dateFormatter = dateFormatter;
2329
}
2430

2531
@Execute
2632
@DescriptionDocs(description = "Shows information about player", arguments = "<player>")
2733
void execute(@Sender Viewer viewer, @Arg Player player) {
28-
this.noticeService.create()
29-
.placeholder("{PLAYER}", player.getName())
30-
.placeholder("{UUID}", String.valueOf(player.getUniqueId()))
31-
.placeholder("{IP}", player.getAddress().getHostString())
32-
.placeholder("{WALK-SPEED}", String.valueOf(player.getWalkSpeed()))
33-
.placeholder("{SPEED}", String.valueOf(player.getFlySpeed()))
34-
.placeholder("{PING}", String.valueOf(player.getPing()))
35-
.placeholder("{LEVEL}", String.valueOf(player.getLevel()))
36-
.placeholder("{HEALTH}", String.valueOf(Math.round(player.getHealthScale())))
37-
.placeholder("{FOOD}", String.valueOf(player.getFoodLevel()))
38-
.messages(translation -> translation.whois().info())
39-
.viewer(viewer)
40-
.send();
34+
this.userManager.findOrCreate(player.getUniqueId(), player.getName())
35+
.thenAccept(user -> this.noticeService.create()
36+
.placeholder("{PLAYER}", player.getName())
37+
.placeholder("{UUID}", String.valueOf(player.getUniqueId()))
38+
.placeholder("{IP}", player.getAddress().getHostString())
39+
.placeholder("{WALK-SPEED}", String.valueOf(player.getWalkSpeed()))
40+
.placeholder("{SPEED}", String.valueOf(player.getFlySpeed()))
41+
.placeholder("{PING}", String.valueOf(player.getPing()))
42+
.placeholder("{LEVEL}", String.valueOf(player.getLevel()))
43+
.placeholder("{HEALTH}", String.valueOf(Math.round(player.getHealthScale())))
44+
.placeholder("{FOOD}", String.valueOf(player.getFoodLevel()))
45+
.placeholder("{LAST-SEEN}", this.dateFormatter.format(user.getLastSeen()))
46+
.placeholder("{ACCOUNT-CREATED}", this.dateFormatter.format(user.getAccountCreated()))
47+
.messages(translation -> translation.whois().info())
48+
.viewer(viewer)
49+
.send());
4150
}
4251
}

eternalcore-core/src/main/java/com/eternalcode/core/user/LoadUserController.java

Lines changed: 0 additions & 34 deletions
This file was deleted.

0 commit comments

Comments
 (0)