Skip to content

Commit 240d7a4

Browse files
committed
request to join nation and accept invitations to join
1 parent 533f622 commit 240d7a4

File tree

9 files changed

+488
-17
lines changed

9 files changed

+488
-17
lines changed
Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
package pro.cloudnode.smp.smpcore;
2+
3+
import net.kyori.adventure.audience.Audience;
4+
import org.bukkit.entity.Player;
5+
import org.jetbrains.annotations.NotNull;
6+
import org.jetbrains.annotations.Nullable;
7+
import pro.cloudnode.smp.smpcore.command.Command;
8+
9+
import java.sql.Connection;
10+
import java.sql.PreparedStatement;
11+
import java.sql.ResultSet;
12+
import java.sql.SQLException;
13+
import java.sql.Timestamp;
14+
import java.util.ArrayList;
15+
import java.util.Date;
16+
import java.util.List;
17+
import java.util.Optional;
18+
import java.util.UUID;
19+
import java.util.logging.Level;
20+
21+
public final class CitizenRequest {
22+
/**
23+
* Member UUID
24+
*/
25+
public final @NotNull UUID uuid;
26+
27+
/**
28+
* Nation ID
29+
*/
30+
public final @NotNull String nationID;
31+
32+
/**
33+
* Request mode. True if the member requests citizenship, false if the nation invites the member.
34+
*/
35+
public final boolean mode;
36+
37+
/**
38+
* Request creation timestamp
39+
*/
40+
public final @NotNull Date created;
41+
42+
/**
43+
* Request expiration timestamp
44+
*/
45+
public final @NotNull Date expires;
46+
47+
/**
48+
* @param uuid Member UUID
49+
* @param nationID Nation ID
50+
* @param mode Request mode. True if the member requests citizenship, false if the nation invites the member.
51+
* @param created Request creation timestamp
52+
* @param expires Request expiration timestamp
53+
*/
54+
public CitizenRequest(
55+
final @NotNull UUID uuid,
56+
final @NotNull String nationID,
57+
final boolean mode,
58+
final @NotNull Date created,
59+
final @NotNull Date expires
60+
) {
61+
this.uuid = uuid;
62+
this.nationID = nationID;
63+
this.mode = mode;
64+
this.created = created;
65+
this.expires = expires;
66+
}
67+
68+
/**
69+
* Checks whether this request has expired
70+
*/
71+
public boolean expired() {
72+
return new Date().after(expires);
73+
}
74+
75+
/**
76+
* Gets the member
77+
*/
78+
public @NotNull Member member() {
79+
return Member.get(uuid).orElseThrow(() -> new IllegalArgumentException("Member not found"));
80+
}
81+
82+
/**
83+
* Gets the nation
84+
*/
85+
public @NotNull Nation nation() {
86+
return Nation.get(nationID).orElseThrow(() -> new IllegalArgumentException("Nation not found"));
87+
}
88+
89+
public boolean send() {
90+
final @NotNull Member member = member();
91+
final @Nullable Player player = member.player().getPlayer();
92+
final @NotNull Nation nation = nation();
93+
if (player != null)
94+
player.sendMessage(SMPCore.messages().nationJoinRequestSent(nation));
95+
return Command.sendMessage(
96+
Audience.audience(
97+
nation().onlinePlayers().stream()
98+
.filter(p -> p.hasPermission(Permission.NATION_JOIN_REQUEST_ACCEPT))
99+
.toList()
100+
),
101+
SMPCore.messages().nationJoinRequestReceived(member)
102+
);
103+
}
104+
105+
/**
106+
* Accepts the request
107+
*/
108+
public void accept() {
109+
nation().add(member());
110+
delete();
111+
}
112+
113+
/**
114+
* Rejects the request
115+
*/
116+
public void reject() {
117+
delete();
118+
}
119+
120+
public CitizenRequest(final @NotNull ResultSet rs) throws SQLException {
121+
this(
122+
UUID.fromString(rs.getString("member")),
123+
rs.getString("nation"),
124+
rs.getBoolean("mode"),
125+
rs.getTimestamp("created"),
126+
rs.getTimestamp("expires")
127+
);
128+
}
129+
130+
public void save() {
131+
try (
132+
final @NotNull Connection conn = SMPCore.getInstance().db().getConnection();
133+
final @NotNull PreparedStatement stmt = conn.prepareStatement(
134+
"INSERT INTO `citizen_requests` (`member`, `nation`, `mode`, `created`, `expires`) VALUES (?,"
135+
+ " ?, ?, ?, ?)")
136+
) {
137+
stmt.setString(1, uuid.toString());
138+
stmt.setString(2, nationID);
139+
stmt.setBoolean(3, mode);
140+
stmt.setTimestamp(4, new Timestamp(created.getTime()));
141+
stmt.setTimestamp(5, new Timestamp(expires.getTime()));
142+
stmt.executeUpdate();
143+
}
144+
catch (final @NotNull SQLException e) {
145+
SMPCore.getInstance()
146+
.getLogger()
147+
.log(
148+
Level.SEVERE,
149+
"could not save citizen request for member: " + uuid + ", nation: " + nationID,
150+
e
151+
);
152+
}
153+
}
154+
155+
public void delete() {
156+
try (
157+
final @NotNull Connection conn = SMPCore.getInstance().db().getConnection();
158+
final @NotNull PreparedStatement stmt = conn.prepareStatement(
159+
"DELETE FROM `citizen_requests` WHERE `member` = ? AND `nation` = ?")
160+
) {
161+
stmt.setString(1, uuid.toString());
162+
stmt.setString(2, nationID);
163+
stmt.executeUpdate();
164+
}
165+
catch (final @NotNull SQLException e) {
166+
SMPCore.getInstance()
167+
.getLogger()
168+
.log(
169+
Level.SEVERE,
170+
"could not delete citizen request for member: " + uuid + ", nation: " + nationID,
171+
e
172+
);
173+
}
174+
}
175+
176+
/**
177+
* Gets a citizen request
178+
*
179+
* @param member Member
180+
* @param nation Nation
181+
*/
182+
public static @NotNull Optional<@NotNull CitizenRequest> get(
183+
final @NotNull Member member,
184+
final @NotNull Nation nation
185+
) {
186+
try (
187+
final @NotNull Connection conn = SMPCore.getInstance().db().getConnection();
188+
final @NotNull PreparedStatement stmt = conn.prepareStatement(
189+
"SELECT * FROM `citizen_requests` WHERE `member` = ? AND `nation` = ? LIMIT 1")
190+
) {
191+
stmt.setString(1, member.uuid.toString());
192+
stmt.setString(2, nation.id);
193+
final @NotNull ResultSet rs = stmt.executeQuery();
194+
if (!rs.next())
195+
return Optional.empty();
196+
return Optional.of(new CitizenRequest(rs));
197+
}
198+
catch (final @NotNull SQLException e) {
199+
SMPCore.getInstance().getLogger().log(
200+
Level.SEVERE,
201+
"could not get citizen request for member: " + member.uuid + ", nation: " + nation.id,
202+
e
203+
);
204+
return Optional.empty();
205+
}
206+
}
207+
208+
/**
209+
* Gets all requests for joining the nation
210+
*
211+
* @param nation Nation
212+
* @param mode Request mode (true for citizen requests, false for nation invitations)
213+
*/
214+
public static @NotNull List<@NotNull CitizenRequest> get(final @NotNull Nation nation, final boolean mode) {
215+
try (
216+
final @NotNull Connection conn = SMPCore.getInstance().db().getConnection();
217+
final @NotNull PreparedStatement stmt = conn.prepareStatement(
218+
"SELECT * FROM `citizen_requests` WHERE `nation` = ? AND `mode` = ? ORDER BY `created`")
219+
) {
220+
stmt.setString(1, nation.id);
221+
stmt.setBoolean(2, mode);
222+
final @NotNull ResultSet rs = stmt.executeQuery();
223+
final @NotNull List<@NotNull CitizenRequest> requests = new ArrayList<>();
224+
while (rs.next())
225+
requests.add(new CitizenRequest(rs));
226+
return requests;
227+
}
228+
catch (final @NotNull SQLException e) {
229+
SMPCore.getInstance()
230+
.getLogger()
231+
.log(Level.SEVERE, "could not get citizen requests for nation: " + nation.id + ", mode: " + mode, e);
232+
return new ArrayList<>();
233+
}
234+
}
235+
236+
/**
237+
* Gets all requests for joining any nation for the member
238+
*
239+
* @param member Member
240+
* @param mode Request mode (true for citizen requests, false for nation invitations)
241+
*/
242+
public static @NotNull List<@NotNull CitizenRequest> get(final @NotNull Member member, final boolean mode) {
243+
try (
244+
final @NotNull Connection conn = SMPCore.getInstance().db().getConnection();
245+
final @NotNull PreparedStatement stmt = conn.prepareStatement(
246+
"SELECT * FROM `citizen_requests` WHERE `member` = ? AND `mode` = ? ORDER BY `created`")
247+
) {
248+
stmt.setString(1, member.uuid.toString());
249+
stmt.setBoolean(2, mode);
250+
final @NotNull ResultSet rs = stmt.executeQuery();
251+
final @NotNull List<@NotNull CitizenRequest> requests = new ArrayList<>();
252+
while (rs.next())
253+
requests.add(new CitizenRequest(rs));
254+
return requests;
255+
}
256+
catch (final @NotNull SQLException e) {
257+
SMPCore.getInstance()
258+
.getLogger()
259+
.log(
260+
Level.SEVERE,
261+
"could not get citizen requests for member: " + member.uuid + ", mode: " + mode,
262+
e
263+
);
264+
return new ArrayList<>();
265+
}
266+
}
267+
}

src/main/java/pro/cloudnode/smp/smpcore/Configuration.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ public int altsMax() {
3535
return config.getInt("alts.max");
3636
}
3737

38+
/**
39+
* The number of minutes after which requests/invitations to join a nation expire
40+
*/
41+
public int joinRequestExpireMinutes() {
42+
return config.getInt("join.request-expire-minutes");
43+
}
44+
3845
public @NotNull Component relativeTime(final int t, final @NotNull ChronoUnit unit) {
3946
final @NotNull String formatString = Objects.requireNonNull(config.getString("relative-time." + switch (unit) {
4047
case SECONDS -> "seconds";

src/main/java/pro/cloudnode/smp/smpcore/Messages.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,29 @@ public Messages() {
300300
.ofNullable(member.player().getName()).orElse(member.uuid.toString())));
301301
}
302302

303+
public @NotNull Component nationJoinRequestSent(final @NotNull Nation nation) {
304+
return MiniMessage.miniMessage()
305+
.deserialize(Objects.requireNonNull(config.getString("nation.join.request-sent")), Placeholder.unparsed("nation", nation.name));
306+
}
307+
308+
public @NotNull Component nationJoinRequestReceived(final @NotNull Member member) {
309+
return MiniMessage.miniMessage()
310+
.deserialize(Objects.requireNonNull(config.getString("nation.join.request-received")), Placeholder.unparsed("player", Optional
311+
.ofNullable(member.player().getName()).orElse(member.uuid.toString())));
312+
}
313+
314+
public @NotNull Component nationJoinJoined(final @NotNull Member member) {
315+
return MiniMessage.miniMessage()
316+
.deserialize(Objects.requireNonNull(config.getString("nation.join.joined")), Placeholder.unparsed("player", Optional
317+
.ofNullable(member.player().getName()).orElse(member.uuid.toString())));
318+
}
319+
320+
public @NotNull Component nationJoinLeft(final @NotNull Member member) {
321+
return MiniMessage.miniMessage()
322+
.deserialize(Objects.requireNonNull(config.getString("nation.join.left")), Placeholder.unparsed("player", Optional
323+
.ofNullable(member.player().getName()).orElse(member.uuid.toString())));
324+
}
325+
303326
// errors
304327

305328
public @NotNull Component errorNoPermission() {
@@ -374,7 +397,7 @@ public Messages() {
374397
.deserialize(Objects.requireNonNull(config.getString("error.command-on-staff")), Placeholder.unparsed("command", label));
375398
}
376399

377-
public @NotNull Component errorNotCitizenYou() {
400+
public @NotNull Component errorNotCitizen() {
378401
return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("error.not-citizen-you")));
379402
}
380403

@@ -384,6 +407,14 @@ public Messages() {
384407
.ofNullable(member.player().getName()).orElse(member.player().getUniqueId().toString())));
385408
}
386409

410+
public @NotNull Component errorAlreadyCitizen() {
411+
return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("error.already-citizen")));
412+
}
413+
414+
public @NotNull Component errorAlreadyCitizen(final @NotNull Nation nation) {
415+
return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("error.already-citizen-nation")), Placeholder.unparsed("nation", nation.name));
416+
}
417+
387418
public @NotNull Component errorNotPlayer() {
388419
return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("error.not-player")));
389420
}
@@ -392,10 +423,18 @@ public Messages() {
392423
return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("error.kick-leadership")));
393424
}
394425

395-
public @NotNull Component nationNotFound(final @NotNull String nation) {
426+
public @NotNull Component errorNationNotFound(final @NotNull String nation) {
396427
return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("error.nation-not-found")), Placeholder.unparsed("nation", nation));
397428
}
398429

430+
public @NotNull Component errorNotInvited(final @NotNull Nation nation) {
431+
return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("error.not-invited")), Placeholder.unparsed("nation", nation.name));
432+
}
433+
434+
public @NotNull Component errorAlreadyRequestedJoin(final @NotNull Nation nation) {
435+
return MiniMessage.miniMessage().deserialize(Objects.requireNonNull(config.getString("error.already-requested-join")), Placeholder.unparsed("nation", nation.name));
436+
}
437+
399438
public record SubCommandArgument(@NotNull String name, boolean required) {
400439
public @NotNull Component component() {
401440
return required ? SMPCore.messages().subCommandArgumentRequired(name) : SMPCore.messages()

0 commit comments

Comments
 (0)