Skip to content

Commit 08caf07

Browse files
author
burdo
committed
introduce basic luckperms api
1 parent 2009b3a commit 08caf07

23 files changed

Lines changed: 451 additions & 0 deletions

src/main/java/org/comroid/api/model/Authentication.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ public Map.Entry<String, String> toHttpBasicHeader() {
4848
"Basic " + Base64.encode(username + ':' + passkey));
4949
}
5050

51+
public Map.Entry<String, String> toBearerTokenHeader() {
52+
Constraint.notNull(passkey, "passkey").run();
53+
54+
return new AbstractMap.SimpleImmutableEntry<>("Authorization", "Bearer " + passkey);
55+
}
56+
5157
public enum Type {
5258
Anonymous, UsernamePassword, UsernameToken, OnlyUsername, Token
5359
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package org.comroid.api.net.luckperms;
2+
3+
import lombok.Builder;
4+
import lombok.Value;
5+
import lombok.experimental.NonFinal;
6+
import org.comroid.api.data.seri.DataNode;
7+
import org.comroid.api.model.Authentication;
8+
import org.comroid.api.net.REST;
9+
import org.comroid.api.net.luckperms.component.GroupsApi;
10+
import org.comroid.api.net.luckperms.component.MiscApi;
11+
import org.comroid.api.net.luckperms.component.TracksApi;
12+
import org.comroid.api.net.luckperms.component.UserApi;
13+
import org.comroid.api.net.luckperms.model.LuckPermsApiCore;
14+
import org.comroid.api.tree.Component;
15+
16+
import java.util.concurrent.CompletableFuture;
17+
18+
@Value
19+
@Builder
20+
@NonFinal
21+
public class LuckPermsApiWrapper extends Component.Base implements LuckPermsApiCore {
22+
@lombok.Builder.Default REST rest = REST.Default;
23+
String baseUrl;
24+
Authentication credentials;
25+
26+
{
27+
addChildren(new UserApi(this),
28+
new GroupsApi(this),
29+
new TracksApi(this),
30+
//todo: new ActionsApi(this),
31+
//todo: new MessagingApi(this),
32+
//todo: new EventApi(this),
33+
new MiscApi(this));
34+
}
35+
36+
@Override
37+
public REST.Request request(REST.Method method, String path) {
38+
return rest.new Request(method, baseUrl + path).addHeader("Accept", "application/json")
39+
.addHeader("Authorization", credentials.toBearerTokenHeader().getValue());
40+
}
41+
42+
@Override
43+
public CompletableFuture<DataNode> get(String path) {
44+
return request(REST.Method.GET, path).execute()
45+
.thenApply(REST.Response::validate2xxOK)
46+
.thenApply(REST.Response::getBody);
47+
}
48+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package org.comroid.api.net.luckperms.component;
2+
3+
import lombok.Value;
4+
import org.comroid.api.data.seri.DataNode;
5+
import org.comroid.api.net.luckperms.model.LuckPermsApiComponent;
6+
import org.comroid.api.net.luckperms.model.LuckPermsApiCore;
7+
import org.comroid.api.net.luckperms.model.ObjectRepository;
8+
import org.comroid.api.net.luckperms.model.dto.Metadata;
9+
import org.comroid.api.net.luckperms.model.dto.PermissionCheckResult;
10+
import org.comroid.api.net.luckperms.model.group.GroupData;
11+
import org.comroid.api.net.luckperms.model.group.GroupSearchResult;
12+
import org.comroid.api.net.luckperms.model.node.Node;
13+
import org.comroid.api.net.luckperms.model.node.NodeContainer;
14+
import org.comroid.api.net.luckperms.model.node.NodeType;
15+
import org.jetbrains.annotations.Nullable;
16+
17+
import java.util.Collection;
18+
import java.util.concurrent.CompletableFuture;
19+
20+
@Value
21+
public class GroupsApi extends LuckPermsApiComponent
22+
implements NodeContainer<String>, ObjectRepository<String, GroupData> {
23+
public GroupsApi(LuckPermsApiCore lpApi) {
24+
super(lpApi);
25+
}
26+
27+
@Override
28+
public CompletableFuture<Collection<String>> getIDs() {
29+
return getLpApi().get("/group").thenApply(data -> data.asArray().stream().map(DataNode::asString).toList());
30+
}
31+
32+
@Override
33+
public CompletableFuture<GroupData> get(String name) {
34+
return getLpApi().get("/group/" + name).thenApply(data -> data.as(GroupData.class).assertion());
35+
}
36+
37+
@lombok.Builder(builderMethodName = "search", buildMethodName = "execute", builderClassName = "SearchQuery")
38+
public CompletableFuture<Collection<GroupSearchResult>> searchQuery(
39+
@Nullable String nodeKey, @Nullable String nodeKeyStartsWith, @Nullable String metaKey,
40+
@Nullable NodeType nodeType, @Nullable String group
41+
) {
42+
var separator = '?';
43+
var path = "/group/search";
44+
45+
if (nodeKey != null) {
46+
path += separator + "key=" + nodeKey;
47+
separator = '&';
48+
}
49+
if (nodeKeyStartsWith != null) {
50+
path += separator + "keyStartsWith=" + nodeKeyStartsWith;
51+
separator = '&';
52+
}
53+
if (metaKey != null) {
54+
path += separator + "metaKey=" + metaKey;
55+
separator = '&';
56+
}
57+
if (nodeType != null) {
58+
path += separator + "type=" + nodeType.name();
59+
separator = '&';
60+
}
61+
if (group != null) {
62+
path += separator + "group=" + group;
63+
separator = 0;
64+
}
65+
66+
if (separator == '?') throw new IllegalArgumentException("At least one parameter must be provided");
67+
return getLpApi().get(path)
68+
.thenApply(data -> data.asArray()
69+
.stream()
70+
.map(node -> node.as(GroupSearchResult.class).assertion())
71+
.toList());
72+
}
73+
74+
@Override
75+
public CompletableFuture<Collection<Node>> getNodes(String name) {
76+
return getLpApi().get("/group/" + name + "/nodes")
77+
.thenApply(data -> data.asArray().stream().map(node -> node.as(Node.class).assertion()).toList());
78+
}
79+
80+
@Override
81+
public CompletableFuture<Metadata> getMetadata(String name) {
82+
return getLpApi().get("/group/" + name + "/meta").thenApply(data -> data.as(Metadata.class).assertion());
83+
}
84+
85+
@Override
86+
public CompletableFuture<PermissionCheckResult> checkPermission(String name, CharSequence permission) {
87+
return getLpApi().get("/group/" + name + "/permission-check?permission=" + permission)
88+
.thenApply(data -> data.as(PermissionCheckResult.class).assertion());
89+
}
90+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.comroid.api.net.luckperms.component;
2+
3+
import lombok.Value;
4+
import org.comroid.api.net.luckperms.model.LuckPermsApiComponent;
5+
import org.comroid.api.net.luckperms.model.LuckPermsApiCore;
6+
import org.comroid.api.net.luckperms.model.dto.HealthResult;
7+
8+
import java.util.concurrent.CompletableFuture;
9+
10+
@Value
11+
public class MiscApi extends LuckPermsApiComponent {
12+
public MiscApi(LuckPermsApiCore lpApi) {
13+
super(lpApi);
14+
}
15+
16+
public CompletableFuture<HealthResult> getHealth() {
17+
return getLpApi().get("/health").thenApply(data -> data.as(HealthResult.class).assertion());
18+
}
19+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.comroid.api.net.luckperms.component;
2+
3+
import lombok.Value;
4+
import org.comroid.api.data.seri.DataNode;
5+
import org.comroid.api.net.luckperms.model.LuckPermsApiComponent;
6+
import org.comroid.api.net.luckperms.model.LuckPermsApiCore;
7+
import org.comroid.api.net.luckperms.model.ObjectRepository;
8+
import org.comroid.api.net.luckperms.model.track.TrackData;
9+
10+
import java.util.Collection;
11+
import java.util.concurrent.CompletableFuture;
12+
13+
@Value
14+
public class TracksApi extends LuckPermsApiComponent implements ObjectRepository<String, TrackData> {
15+
public TracksApi(LuckPermsApiCore lpApi) {
16+
super(lpApi);
17+
}
18+
19+
@Override
20+
public CompletableFuture<Collection<String>> getIDs() {
21+
return getLpApi().get("/track").thenApply(data -> data.asArray().stream().map(DataNode::asString).toList());
22+
}
23+
24+
@Override
25+
public CompletableFuture<TrackData> get(String name) {
26+
return getLpApi().get("/track/" + name).thenApply(data -> data.as(TrackData.class).assertion());
27+
}
28+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package org.comroid.api.net.luckperms.component;
2+
3+
import lombok.Value;
4+
import org.comroid.api.data.seri.DataNode;
5+
import org.comroid.api.net.luckperms.model.LuckPermsApiComponent;
6+
import org.comroid.api.net.luckperms.model.LuckPermsApiCore;
7+
import org.comroid.api.net.luckperms.model.ObjectRepository;
8+
import org.comroid.api.net.luckperms.model.dto.Metadata;
9+
import org.comroid.api.net.luckperms.model.dto.PermissionCheckResult;
10+
import org.comroid.api.net.luckperms.model.node.Node;
11+
import org.comroid.api.net.luckperms.model.node.NodeContainer;
12+
import org.comroid.api.net.luckperms.model.node.NodeType;
13+
import org.comroid.api.net.luckperms.model.user.PlayerData;
14+
import org.comroid.api.net.luckperms.model.user.UserData;
15+
import org.comroid.api.net.luckperms.model.user.UserSearchResult;
16+
import org.jetbrains.annotations.Nullable;
17+
18+
import java.util.Collection;
19+
import java.util.Objects;
20+
import java.util.UUID;
21+
import java.util.concurrent.CompletableFuture;
22+
23+
@Value
24+
@SuppressWarnings("unused")
25+
public class UserApi extends LuckPermsApiComponent implements NodeContainer<UUID>, ObjectRepository<UUID, UserData> {
26+
public UserApi(LuckPermsApiCore lpApi) {
27+
super(lpApi);
28+
}
29+
30+
@Override
31+
public CompletableFuture<Collection<UUID>> getIDs() {
32+
return getLpApi().get("/user")
33+
.thenApply(data -> data.asArray()
34+
.stream()
35+
.map(DataNode::asString)
36+
.filter(Objects::nonNull)
37+
.map(UUID::fromString)
38+
.toList());
39+
}
40+
41+
@Override
42+
public CompletableFuture<UserData> get(UUID uniqueId) {
43+
return getLpApi().get("/user/" + uniqueId).thenApply(data -> data.as(UserData.class).assertion());
44+
}
45+
46+
@lombok.Builder(builderMethodName = "lookup", buildMethodName = "execute", builderClassName = "LookupQuery")
47+
public CompletableFuture<PlayerData> lookupQuery(@Nullable String username, @Nullable UUID uniqueId) {
48+
var path = "/user/lookup";
49+
if (username != null) path += "?username=" + username;
50+
else if (uniqueId != null) path += "?uniqueId=" + uniqueId;
51+
else throw new IllegalArgumentException("One of ['username', 'uniqueId'] must be provided");
52+
return getLpApi().get(path).thenApply(data -> data.as(PlayerData.class).assertion());
53+
}
54+
55+
@lombok.Builder(builderMethodName = "search", buildMethodName = "execute", builderClassName = "SearchQuery")
56+
public CompletableFuture<Collection<UserSearchResult>> searchQuery(
57+
@Nullable String nodeKey, @Nullable String nodeKeyStartsWith, @Nullable String metaKey,
58+
@Nullable NodeType nodeType, @Nullable String group
59+
) {
60+
var separator = '?';
61+
var path = "/user/search";
62+
63+
if (nodeKey != null) {
64+
path += separator + "key=" + nodeKey;
65+
separator = '&';
66+
}
67+
if (nodeKeyStartsWith != null) {
68+
path += separator + "keyStartsWith=" + nodeKeyStartsWith;
69+
separator = '&';
70+
}
71+
if (metaKey != null) {
72+
path += separator + "metaKey=" + metaKey;
73+
separator = '&';
74+
}
75+
if (nodeType != null) {
76+
path += separator + "type=" + nodeType.name();
77+
separator = '&';
78+
}
79+
if (group != null) {
80+
path += separator + "group=" + group;
81+
separator = 0;
82+
}
83+
84+
if (separator == '?') throw new IllegalArgumentException("At least one parameter must be provided");
85+
return getLpApi().get(path)
86+
.thenApply(data -> data.asArray()
87+
.stream()
88+
.map(node -> node.as(UserSearchResult.class).assertion())
89+
.toList());
90+
}
91+
92+
@Override
93+
public CompletableFuture<Collection<Node>> getNodes(UUID uniqueId) {
94+
return getLpApi().get("/user/" + uniqueId + "/nodes")
95+
.thenApply(data -> data.asArray().stream().map(node -> node.as(Node.class).assertion())
96+
97+
.toList());
98+
}
99+
100+
@Override
101+
public CompletableFuture<Metadata> getMetadata(UUID uniqueId) {
102+
return getLpApi().get("/user/" + uniqueId + "/meta").thenApply(data -> data.as(Metadata.class).assertion());
103+
}
104+
105+
@Override
106+
public CompletableFuture<PermissionCheckResult> checkPermission(UUID uniqueId, CharSequence permission) {
107+
return getLpApi().get("/user/" + uniqueId + "/permission-check?permission=" + permission)
108+
.thenApply(data -> data.as(PermissionCheckResult.class).assertion());
109+
}
110+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.comroid.api.net.luckperms.model;
2+
3+
import lombok.Value;
4+
import lombok.experimental.NonFinal;
5+
import org.comroid.api.tree.Component;
6+
7+
@Value
8+
@NonFinal
9+
public abstract class LuckPermsApiComponent extends Component.Base {
10+
LuckPermsApiCore lpApi;
11+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.comroid.api.net.luckperms.model;
2+
3+
import org.comroid.api.data.seri.DataNode;
4+
import org.comroid.api.model.Authentication;
5+
import org.comroid.api.net.REST;
6+
import org.comroid.api.tree.Component;
7+
8+
import java.util.concurrent.CompletableFuture;
9+
10+
public interface LuckPermsApiCore extends Component {
11+
String getBaseUrl();
12+
13+
REST getRest();
14+
15+
Authentication getCredentials();
16+
17+
REST.Request request(REST.Method method, String path);
18+
19+
CompletableFuture<DataNode> get(String path);
20+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.comroid.api.net.luckperms.model;
2+
3+
import java.util.Collection;
4+
import java.util.concurrent.CompletableFuture;
5+
6+
public interface ObjectRepository<ID, T> {
7+
CompletableFuture<Collection<ID>> getIDs();
8+
9+
CompletableFuture<T> get(ID key);
10+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.comroid.api.net.luckperms.model.dto;
2+
3+
public record ContextEntry(String key, String value) {
4+
}

0 commit comments

Comments
 (0)