Skip to content

Commit e167bfc

Browse files
authored
Manage nation members (#27)
2 parents 7fa9514 + f800955 commit e167bfc

File tree

17 files changed

+1752
-14
lines changed

17 files changed

+1752
-14
lines changed

.run/Package.run.xml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="Package" type="MavenRunConfiguration" factoryName="Maven">
3+
<MavenSettings>
4+
<option name="myGeneralSettings" />
5+
<option name="myRunnerSettings" />
6+
<option name="myRunnerParameters">
7+
<MavenRunnerParameters>
8+
<option name="cmdOptions" />
9+
<option name="profiles">
10+
<set />
11+
</option>
12+
<option name="goals">
13+
<list>
14+
<option value="package" />
15+
</list>
16+
</option>
17+
<option name="multimoduleDir" />
18+
<option name="pomFileName" />
19+
<option name="profilesMap">
20+
<map />
21+
</option>
22+
<option name="projectsCmdOptionValues">
23+
<list />
24+
</option>
25+
<option name="resolveToWorkspace" value="false" />
26+
<option name="workingDirPath" value="$PROJECT_DIR$" />
27+
</MavenRunnerParameters>
28+
</option>
29+
</MavenSettings>
30+
<method v="2" />
31+
</configuration>
32+
</component>
Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
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+
import java.util.stream.Collectors;
21+
22+
public final class CitizenRequest {
23+
/**
24+
* Member UUID
25+
*/
26+
public final @NotNull UUID uuid;
27+
28+
/**
29+
* Nation ID
30+
*/
31+
public final @NotNull String nationID;
32+
33+
/**
34+
* Request mode. True if the member requests citizenship, false if the nation invites the member.
35+
*/
36+
public final boolean mode;
37+
38+
/**
39+
* Request creation timestamp
40+
*/
41+
public final @NotNull Date created;
42+
43+
/**
44+
* Request expiration timestamp
45+
*/
46+
public final @NotNull Date expires;
47+
48+
/**
49+
* @param uuid Member UUID
50+
* @param nationID Nation ID
51+
* @param mode Request mode. True if the member requests citizenship, false if the nation invites the member.
52+
* @param created Request creation timestamp
53+
* @param expires Request expiration timestamp
54+
*/
55+
public CitizenRequest(
56+
final @NotNull UUID uuid,
57+
final @NotNull String nationID,
58+
final boolean mode,
59+
final @NotNull Date created,
60+
final @NotNull Date expires
61+
) {
62+
this.uuid = uuid;
63+
this.nationID = nationID;
64+
this.mode = mode;
65+
this.created = created;
66+
this.expires = expires;
67+
}
68+
69+
/**
70+
* Checks whether this request has expired
71+
*/
72+
public boolean expired() {
73+
return new Date().after(expires);
74+
}
75+
76+
/**
77+
* Gets the member
78+
*/
79+
public @NotNull Member member() {
80+
return Member.get(uuid).orElseThrow(() -> new IllegalArgumentException("Member not found"));
81+
}
82+
83+
/**
84+
* Gets the nation
85+
*/
86+
public @NotNull Nation nation() {
87+
return Nation.get(nationID).orElseThrow(() -> new IllegalArgumentException("Nation not found"));
88+
}
89+
90+
public boolean send() {
91+
final @NotNull Member member = member();
92+
final @Nullable Player player = member.player().getPlayer();
93+
final @NotNull Nation nation = nation();
94+
95+
// invited
96+
if (!mode) {
97+
if (player != null)
98+
player.sendMessage(SMPCore.messages().nationJoinInviteReceived(nation));
99+
return true;
100+
}
101+
102+
// requested
103+
return Command.sendMessage(
104+
Audience.audience(
105+
nation().onlinePlayers().stream()
106+
.filter(p -> p.hasPermission(Permission.NATION_INVITE))
107+
.toList()
108+
),
109+
SMPCore.messages().nationJoinRequestReceived(member)
110+
);
111+
}
112+
113+
/**
114+
* Accepts the request
115+
*/
116+
public void accept() {
117+
nation().add(member());
118+
delete();
119+
}
120+
121+
/**
122+
* Rejects the request
123+
*/
124+
public void reject() {
125+
delete();
126+
}
127+
128+
public CitizenRequest(final @NotNull ResultSet rs) throws SQLException {
129+
this(
130+
UUID.fromString(rs.getString("member")),
131+
rs.getString("nation"),
132+
rs.getBoolean("mode"),
133+
rs.getTimestamp("created"),
134+
rs.getTimestamp("expires")
135+
);
136+
}
137+
138+
public void save() {
139+
try (
140+
final @NotNull Connection conn = SMPCore.getInstance().db().getConnection();
141+
final @NotNull PreparedStatement stmt = conn.prepareStatement(
142+
"INSERT INTO `citizen_requests` (`member`, `nation`, `mode`, `created`, `expires`) VALUES (?,"
143+
+ " ?, ?, ?, ?)")
144+
) {
145+
stmt.setString(1, uuid.toString());
146+
stmt.setString(2, nationID);
147+
stmt.setBoolean(3, mode);
148+
stmt.setTimestamp(4, new Timestamp(created.getTime()));
149+
stmt.setTimestamp(5, new Timestamp(expires.getTime()));
150+
stmt.executeUpdate();
151+
}
152+
catch (final @NotNull SQLException e) {
153+
SMPCore.getInstance()
154+
.getLogger()
155+
.log(
156+
Level.SEVERE,
157+
"could not save citizen request for member: " + uuid + ", nation: " + nationID,
158+
e
159+
);
160+
}
161+
}
162+
163+
public void delete() {
164+
try (
165+
final @NotNull Connection conn = SMPCore.getInstance().db().getConnection();
166+
final @NotNull PreparedStatement stmt = conn.prepareStatement(
167+
"DELETE FROM `citizen_requests` WHERE `member` = ? AND `nation` = ?")
168+
) {
169+
stmt.setString(1, uuid.toString());
170+
stmt.setString(2, nationID);
171+
stmt.executeUpdate();
172+
}
173+
catch (final @NotNull SQLException e) {
174+
SMPCore.getInstance()
175+
.getLogger()
176+
.log(
177+
Level.SEVERE,
178+
"could not delete citizen request for member: " + uuid + ", nation: " + nationID,
179+
e
180+
);
181+
}
182+
}
183+
184+
/**
185+
* Gets a citizen request
186+
*
187+
* @param member Member
188+
* @param nation Nation
189+
*/
190+
public static @NotNull Optional<@NotNull CitizenRequest> get(
191+
final @NotNull Member member,
192+
final @NotNull Nation nation
193+
) {
194+
try (
195+
final @NotNull Connection conn = SMPCore.getInstance().db().getConnection();
196+
final @NotNull PreparedStatement stmt = conn.prepareStatement(
197+
"SELECT * FROM `citizen_requests` WHERE `member` = ? AND `nation` = ? LIMIT 1")
198+
) {
199+
stmt.setString(1, member.uuid.toString());
200+
stmt.setString(2, nation.id);
201+
final @NotNull ResultSet rs = stmt.executeQuery();
202+
if (!rs.next())
203+
return Optional.empty();
204+
return Optional.of(new CitizenRequest(rs));
205+
}
206+
catch (final @NotNull SQLException e) {
207+
SMPCore.getInstance().getLogger().log(
208+
Level.SEVERE,
209+
"could not get citizen request for member: " + member.uuid + ", nation: " + nation.id,
210+
e
211+
);
212+
return Optional.empty();
213+
}
214+
}
215+
216+
/**
217+
* Gets all requests for joining the nation
218+
*
219+
* @param nation Nation
220+
* @param mode Request mode (true for citizen requests, false for nation invitations)
221+
*/
222+
public static @NotNull List<@NotNull CitizenRequest> get(final @NotNull Nation nation, final boolean mode) {
223+
try (
224+
final @NotNull Connection conn = SMPCore.getInstance().db().getConnection();
225+
final @NotNull PreparedStatement stmt = conn.prepareStatement(
226+
"SELECT * FROM `citizen_requests` WHERE `nation` = ? AND `mode` = ? ORDER BY `created`")
227+
) {
228+
stmt.setString(1, nation.id);
229+
stmt.setBoolean(2, mode);
230+
final @NotNull ResultSet rs = stmt.executeQuery();
231+
final @NotNull List<@NotNull CitizenRequest> requests = new ArrayList<>();
232+
while (rs.next())
233+
requests.add(new CitizenRequest(rs));
234+
return requests;
235+
}
236+
catch (final @NotNull SQLException e) {
237+
SMPCore.getInstance()
238+
.getLogger()
239+
.log(Level.SEVERE, "could not get citizen requests for nation: " + nation.id + ", mode: " + mode, e);
240+
return new ArrayList<>();
241+
}
242+
}
243+
244+
/**
245+
* Gets all requests for joining any nation for the member
246+
*
247+
* @param member Member
248+
* @param mode Request mode (true for citizen requests, false for nation invitations)
249+
*/
250+
public static @NotNull List<@NotNull CitizenRequest> get(final @NotNull Member member, final boolean mode) {
251+
try (
252+
final @NotNull Connection conn = SMPCore.getInstance().db().getConnection();
253+
final @NotNull PreparedStatement stmt = conn.prepareStatement(
254+
"SELECT * FROM `citizen_requests` WHERE `member` = ? AND `mode` = ? ORDER BY `created`")
255+
) {
256+
stmt.setString(1, member.uuid.toString());
257+
stmt.setBoolean(2, mode);
258+
final @NotNull ResultSet rs = stmt.executeQuery();
259+
final @NotNull List<@NotNull CitizenRequest> requests = new ArrayList<>();
260+
while (rs.next())
261+
requests.add(new CitizenRequest(rs));
262+
return requests;
263+
}
264+
catch (final @NotNull SQLException e) {
265+
SMPCore.getInstance()
266+
.getLogger()
267+
.log(
268+
Level.SEVERE,
269+
"could not get citizen requests for member: " + member.uuid + ", mode: " + mode,
270+
e
271+
);
272+
return new ArrayList<>();
273+
}
274+
}
275+
276+
/**
277+
* Deletes multiple requests
278+
*
279+
* @param requests Requests
280+
*/
281+
public static void delete(final @NotNull List<@NotNull CitizenRequest> requests) {
282+
try (
283+
final @NotNull Connection conn = SMPCore.getInstance().db().getConnection();
284+
final @NotNull PreparedStatement stmt = conn.prepareStatement(
285+
"DELETE FROM `citizen_requests` WHERE `member` = ? AND `nation` = ?")
286+
) {
287+
conn.setAutoCommit(false);
288+
for (final @NotNull CitizenRequest request : requests) {
289+
stmt.setString(1, request.uuid.toString());
290+
stmt.setString(2, request.nationID);
291+
stmt.addBatch();
292+
}
293+
294+
stmt.executeBatch();
295+
conn.commit();
296+
}
297+
catch (final @NotNull SQLException e) {
298+
SMPCore.getInstance().getLogger().log(
299+
Level.SEVERE,
300+
"could not delete citizen requests: "
301+
+ requests.stream()
302+
.map(r -> "(" + r.nationID + ", " + r.uuid + ")")
303+
.collect(Collectors.joining(", ")),
304+
e
305+
);
306+
}
307+
}
308+
}

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";

0 commit comments

Comments
 (0)