SchemNode v2 Draft
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful

Dieser Commit ist enthalten in:
Chaoscaot 2022-09-21 19:53:45 +02:00
Ursprung 9043ab9dc5
Commit 662c3cdd9b
3 geänderte Dateien mit 542 neuen und 321 gelöschten Zeilen

Datei anzeigen

@ -22,6 +22,7 @@ package de.steamwar.sql;
import de.steamwar.sql.internal.Field;
import de.steamwar.sql.internal.SelectStatement;
import de.steamwar.sql.internal.Table;
import de.steamwar.sql.v2.SchematicNode;
import lombok.AllArgsConstructor;
@AllArgsConstructor

Datei anzeigen

@ -19,134 +19,43 @@
package de.steamwar.sql;
import de.steamwar.sql.internal.*;
import lombok.AccessLevel;
import lombok.Setter;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@Deprecated
public class SchematicNode {
static {
new SqlTypeMapper<>(SchematicNode.class, null, (rs, identifier) -> { throw new SecurityException("SchematicNode cannot be used as type (recursive select)"); }, (st, index, value) -> st.setInt(index, value.nodeId));
private static int nullableInt(Integer i) {
return i == null ? 0 : i;
}
private static final Map<Integer, Map<String, List<String>>> TAB_CACHE = new HashMap<>();
public static void clear() {
TAB_CACHE.clear();
}
private static final String[] fields = {"NodeId", "NodeOwner", "NodeName", "ParentNode", "LastUpdate", "NodeItem", "NodeType", "NodeRank", "ReplaceColor", "AllowReplay", "NodeFormat"};
private static String nodeSelectCreator(String itemPrefix) {
return "SELECT " + Arrays.stream(fields).map(s -> itemPrefix + s).collect(Collectors.joining(", ")) + " FROM SchematicNode ";
}
private static final Table<SchematicNode> table = new Table<>(SchematicNode.class);
private static final Statement create = table.insertFields(true, "NodeOwner", "NodeName", "ParentNode", "NodeItem", "NodeType");
private static final Statement update = table.insertAll();
private static final Statement delete = table.delete(Table.PRIMARY);
private static final SelectStatement<SchematicNode> byId = table.select(Table.PRIMARY);
private static final SelectStatement<SchematicNode> byOwnerNameParent = table.select("OwnerNameParent");
private static final SelectStatement<SchematicNode> byOwnerNameParent_null = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE NodeOwner = ? AND NodeName = ? AND ParentNode is NULL");
private static final SelectStatement<SchematicNode> byParent = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE ParentNode = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byParent_null = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE ParentNode is NULL ORDER BY NodeName");
private static final SelectStatement<SchematicNode> dirsByParent = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE ParentNode = ? AND NodeType is NULL ORDER BY NodeName");
private static final SelectStatement<SchematicNode> dirsByParent_null = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE ParentNode is NULL AND NodeType is NULL ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byParentName = table.selectFields("NodeName", "ParentNode");
private static final SelectStatement<SchematicNode> byParentName_null = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE NodeName = ? AND ParentNode is NULL");
private static final SelectStatement<SchematicNode> accessibleByUserTypeParent = new SelectStatement<>(table, "WITH RECURSIVE RSNB AS (WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN WHERE NodeType = ? UNION " + nodeSelectCreator("SN.") + "AS SN, RSNB WHERE SN.NodeId = RSNB.ParentNode)SELECT * FROM RSNB WHERE ParentNode = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> accessibleByUserTypeParent_Null = new SelectStatement<>(table, "WITH RECURSIVE RSNB AS (WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN WHERE NodeType = ? UNION " + nodeSelectCreator("SN.") + "AS SN, RSNB WHERE SN.NodeId = RSNB.ParentNode)SELECT * FROM RSNB WHERE ParentNode is null ORDER BY NodeName");
private static final SelectStatement<SchematicNode> accessibleByUserType = new SelectStatement<>(table, "WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN WHERE NodeType = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byOwnerType = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE NodeOwner = ? AND NodeType = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byType = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE NodeType = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> accessibleByUser = new SelectStatement<>(table, nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) AND ((s.NodeOwner = ? AND s.ParentNode IS NULL) OR NOT s.NodeOwner = ?) GROUP BY s.NodeId ORDER BY s.NodeName");
private static final Statement schematicAccessibleForUser = new Statement("WITH RECURSIVE RSN AS (" + nodeSelectCreator("") + "WHERE NodeId = ? UNION " + nodeSelectCreator("SN.") + "SN, RSN WHERE RSN.ParentNode = SN.NodeId) SELECT COUNT(RSN.NodeId) AS `Accessible` FROM RSN LEFT Join NodeMember NM On NM.NodeId = RSN.NodeId WHERE NodeOwner = ? OR UserId = ? LIMIT 1");
private static final SelectStatement<SchematicNode> allAccessibleByUser = new SelectStatement<>(table, "WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN ORDER BY NodeName");
private static final SelectStatement<SchematicNode> allParentsOfNode = new SelectStatement<>(table, "WITH RECURSIVE RSN AS (" + nodeSelectCreator("") + "WHERE NodeId = ? UNION " + nodeSelectCreator("SN.") + "SN, RSN WHERE RSN.ParentNode = SN.NodeId) SELECT * FROM RSN ORDER BY NodeName");
@Field(keys = {Table.PRIMARY}, autoincrement = true)
private final int nodeId;
@Field(keys = {"OwnerNameParent"})
private final int nodeOwner;
@Field(keys = {"OwnerNameParent"})
private String nodeName;
@Field(keys = {"OwnerNameParent"}, nullable = true)
private Integer parentNode;
@Field(def = "CURRENT_TIMESTAMP")
private Timestamp lastUpdate;
@Field(def = "''")
private String nodeItem;
@Field(def = "'normal'", nullable = true)
private SchematicType nodeType;
@Field(def = "0")
private int nodeRank;
@Field(def = "1")
private boolean replaceColor;
@Field(def = "1")
private boolean allowReplay;
@Setter(AccessLevel.PACKAGE)
@Field(def = "1")
private boolean nodeFormat;
private final de.steamwar.sql.v2.SchematicNode node;
private final Map<Integer, String> brCache = new HashMap<>();
public SchematicNode(
int nodeId,
int nodeOwner,
String nodeName,
Integer parentNode,
Timestamp lastUpdate,
String nodeItem,
SchematicType nodeType,
int nodeRank,
boolean replaceColor,
boolean allowReplay,
boolean nodeFormat
) {
this.nodeId = nodeId;
this.nodeOwner = nodeOwner;
this.nodeName = nodeName;
this.parentNode = parentNode;
this.nodeItem = nodeItem;
this.nodeType = nodeType;
this.lastUpdate = lastUpdate;
this.nodeRank = nodeRank;
this.replaceColor = replaceColor;
this.allowReplay = allowReplay;
this.nodeFormat = nodeFormat;
public SchematicNode(de.steamwar.sql.v2.SchematicNode node) {
this.node = node;
}
public static SchematicNode createSchematic(int owner, String name, Integer parent) {
return createSchematicNode(owner, name, parent, SchematicType.Normal.toDB(), "");
return new SchematicNode(de.steamwar.sql.v2.SchematicNode.createSchematic(SteamwarUser.get(owner), name, nullableInt(parent)));
}
public static SchematicNode createSchematicDirectory(int owner, String name, Integer parent) {
return createSchematicNode(owner, name, parent, null, "");
return new SchematicNode(de.steamwar.sql.v2.SchematicNode.createSchematicNode(SteamwarUser.get(owner), name, nullableInt(parent), null, ""));
}
public static SchematicNode createSchematicNode(int owner, String name, Integer parent, String type, String item) {
if (parent != null && parent == 0)
parent = null;
int nodeId = create.insertGetKey(owner, name, parent, type, item);
return getSchematicNode(nodeId);
return new SchematicNode(de.steamwar.sql.v2.SchematicNode.createSchematicNode(SteamwarUser.get(owner), name, nullableInt(parent), type, item));
}
public static SchematicNode getSchematicNode(int owner, String name, SchematicNode parent) {
return getSchematicNode(owner, name, parent.getId());
return de.steamwar.sql.v2.SchematicNode.getSchematicNode(SteamwarUser.get(owner), name, parent.node).map(SchematicNode::new).orElse(null);
}
public static SchematicNode getSchematicNode(int owner, String name, Integer parent) {
if (parent == null || parent == 0)
return byOwnerNameParent_null.select(owner, name);
return byOwnerNameParent.select(owner, name, parent);
return de.steamwar.sql.v2.SchematicNode.getSchematicNode(SteamwarUser.get(owner), name, de.steamwar.sql.v2.SchematicNode.getSchematicNode(nullableInt(parent))).map(SchematicNode::new).orElse(null);
}
public static List<SchematicNode> getSchematicNodeInNode(SchematicNode parent) {
@ -154,20 +63,11 @@ public class SchematicNode {
}
public static List<SchematicNode> getSchematicNodeInNode(Integer parent) {
if(parent == null || parent == 0) {
rootWarning();
return byParent_null.listSelect();
}
return byParent.listSelect(parent);
return de.steamwar.sql.v2.SchematicNode.getSchematicNodeInNode(de.steamwar.sql.v2.SchematicNode.getSchematicNode(nullableInt(parent))).stream().map(SchematicNode::new).collect(Collectors.toList());
}
public static List<SchematicNode> getSchematicDirectoryInNode(Integer parent) {
if(parent == null || parent == 0) {
rootWarning();
return dirsByParent_null.listSelect();
}
return dirsByParent.listSelect(parent);
return de.steamwar.sql.v2.SchematicNode.getSchematicDirectoryInNode(de.steamwar.sql.v2.SchematicNode.getSchematicNode(nullableInt(parent))).stream().map(SchematicNode::new).collect(Collectors.toList());
}
@Deprecated
@ -181,69 +81,44 @@ public class SchematicNode {
}
public static SchematicNode getSchematicNode(String name, Integer parent) {
if(parent == null || parent == 0) {
rootWarning();
return byParentName_null.select(name);
}
return byParentName.select(name, parent);
return de.steamwar.sql.v2.SchematicNode.getSchematicNode(name, de.steamwar.sql.v2.SchematicNode.getSchematicNode(nullableInt(parent))).map(SchematicNode::new).orElse(null);
}
public static SchematicNode getSchematicNode(int id) {
return byId.select(id);
return new SchematicNode(de.steamwar.sql.v2.SchematicNode.getSchematicNode(id));
}
public static List<SchematicNode> getAccessibleSchematicsOfTypeInParent(int owner, String schemType, Integer parent) {
if(parent == null || parent == 0)
return accessibleByUserTypeParent_Null.listSelect(owner, owner, schemType);
return accessibleByUserTypeParent.listSelect(owner, owner, schemType, parent);
return de.steamwar.sql.v2.SchematicNode.getAccessibleSchematicsOfTypeInParent(SteamwarUser.get(owner), schemType, de.steamwar.sql.v2.SchematicNode.getSchematicNode(nullableInt(parent))).stream().map(SchematicNode::new).collect(Collectors.toList());
}
public static List<SchematicNode> getAllAccessibleSchematicsOfType(int user, String schemType) {
return accessibleByUserType.listSelect(user, user, schemType);
return de.steamwar.sql.v2.SchematicNode.getAllAccessibleSchematicsOfType(SteamwarUser.get(user), SchematicType.fromDB(schemType)).stream().map(SchematicNode::new).collect(Collectors.toList());
}
public static List<SchematicNode> getAllSchematicsOfType(int owner, String schemType) {
return byOwnerType.listSelect(owner, schemType);
return de.steamwar.sql.v2.SchematicNode.getAllSchematicsOfType(SteamwarUser.get(owner), SchematicType.fromDB(schemType)).stream().map(SchematicNode::new).collect(Collectors.toList());
}
@Deprecated
public static List<SchematicNode> getAllSchematicsOfType(String schemType) {
return byType.listSelect(schemType);
return de.steamwar.sql.v2.SchematicNode.getAllSchematicsOfType(SchematicType.fromDB(schemType)).stream().map(SchematicNode::new).collect(Collectors.toList());
}
public static List<SchematicNode> getAllSchematicsOfType(SchematicType schemType) {
return byType.listSelect(schemType);
return de.steamwar.sql.v2.SchematicNode.getAllSchematicsOfType(schemType).stream().map(SchematicNode::new).collect(Collectors.toList());
}
public static List<SchematicNode> deepGet(Integer parent, Predicate<SchematicNode> filter) {
List<SchematicNode> finalList = new ArrayList<>();
List<SchematicNode> nodes = SchematicNode.getSchematicNodeInNode(parent);
nodes.forEach(node -> {
if (node.isDir()) {
finalList.addAll(deepGet(node.getId(), filter));
} else {
if (filter.test(node))
finalList.add(node);
}
});
return finalList;
return de.steamwar.sql.v2.SchematicNode.deepGet(de.steamwar.sql.v2.SchematicNode.getSchematicNode(nullableInt(parent)), schematicNode -> filter.test(new SchematicNode(schematicNode))).stream().map(SchematicNode::new).collect(Collectors.toList());
}
public static List<SchematicNode> getSchematicsAccessibleByUser(int user, Integer parent) {
if (parent == null || parent == 0)
return accessibleByUser.listSelect(user, user, user, user);
if(schematicAccessibleForUser.select(rs -> {
rs.next();
return rs.getInt("Accessible") > 0;
}, parent, user, user))
return getSchematicNodeInNode(parent);
return Collections.emptyList();
return de.steamwar.sql.v2.SchematicNode.getSchematicsAccessibleByUser(SteamwarUser.get(user), de.steamwar.sql.v2.SchematicNode.getSchematicNode(nullableInt(parent))).stream().map(SchematicNode::new).collect(Collectors.toList());
}
public static List<SchematicNode> getAllSchematicsAccessibleByUser(int user) {
return allAccessibleByUser.listSelect(user, user);
return de.steamwar.sql.v2.SchematicNode.getAllSchematicsAccessibleByUser(SteamwarUser.get(user)).stream().map(SchematicNode::new).collect(Collectors.toList());
}
public static List<SchematicNode> getAllParentsOfNode(SchematicNode node) {
@ -251,55 +126,15 @@ public class SchematicNode {
}
public static List<SchematicNode> getAllParentsOfNode(int node) {
return allParentsOfNode.listSelect(node);
return de.steamwar.sql.v2.SchematicNode.getAllParentsOfNode(de.steamwar.sql.v2.SchematicNode.getSchematicNode(node)).stream().map(SchematicNode::new).collect(Collectors.toList());
}
public static SchematicNode getNodeFromPath(SteamwarUser user, String s) {
if (s.startsWith("/")) {
s = s.substring(1);
}
if (s.isEmpty()) {
return null;
}
if (s.contains("/")) {
String[] layers = s.split("/");
SchematicNode currentNode = null;
for (int i = 0; i < layers.length; i++) {
int finalI = i;
Optional<SchematicNode> node;
if (currentNode == null) {
node = SchematicNode.getSchematicsAccessibleByUser(user.getId(), 0).stream().filter(node1 -> node1.getName().equals(layers[finalI])).findAny();
} else {
node = Optional.ofNullable(SchematicNode.getSchematicNode(layers[i], currentNode.getId()));
}
if (!node.isPresent()) {
return null;
} else {
currentNode = node.get();
if (!currentNode.isDir() && i != layers.length - 1) {
return null;
}
}
}
return currentNode;
} else {
String finalS = s;
return SchematicNode.getSchematicsAccessibleByUser(user.getId(), 0).stream().filter(node1 -> node1.getName().equals(finalS)).findAny().orElse(null);
}
return de.steamwar.sql.v2.SchematicNode.getNodeFromPath(user, s).map(SchematicNode::new).orElse(null);
}
public static List<SchematicNode> filterSchems(int user, Predicate<SchematicNode> filter) {
List<SchematicNode> finalList = new ArrayList<>();
List<SchematicNode> nodes = getSchematicsAccessibleByUser(user, null);
nodes.forEach(node -> {
if (node.isDir()) {
finalList.addAll(deepGet(node.getId(), filter));
} else {
if (filter.test(node))
finalList.add(node);
}
});
return finalList;
return de.steamwar.sql.v2.SchematicNode.filterSchems(SteamwarUser.get(user), schematicNode -> filter.test(new SchematicNode(schematicNode))).stream().map(SchematicNode::new).collect(Collectors.toList());
}
@Deprecated
@ -308,236 +143,139 @@ public class SchematicNode {
}
public int getId() {
return nodeId;
return node.getId();
}
public int getOwner() {
return nodeOwner;
return node.getOwner().getId();
}
public String getName() {
return nodeName;
return node.getName();
}
public void setName(String name) {
this.nodeName = name;
updateDB();
node.setName(name);
}
public Integer getParent() {
return parentNode;
return node.getParent() == null ? null : node.getParent().getId();
}
public void setParent(Integer parent) {
this.parentNode = parent;
updateDB();
node.setParent(de.steamwar.sql.v2.SchematicNode.getSchematicNode(nullableInt(parent)));
}
public String getItem() {
if (nodeItem.isEmpty()) {
return isDir() ? "CHEST" : "CAULDRON_ITEM";
}
return nodeItem;
return node.getItem();
}
public void setItem(String item) {
this.nodeItem = item;
updateDB();
node.setItem(item);
}
@Deprecated
public String getType() {
return nodeType.name();
return node.getSchemtype().toDB();
}
@Deprecated
public void setType(String type) {
if(isDir())
throw new SecurityException("Node is Directory");
this.nodeType = SchematicType.fromDB(type);
updateDB();
node.setSchemtype(SchematicType.fromDB(type));
}
public boolean isDir() {
return nodeType == null;
return node.isDir();
}
public boolean getSchemFormat() {
if(isDir())
throw new SecurityException("Node is Directory");
return nodeFormat;
return node.getSchemFormat();
}
public int getRank() {
if(isDir())
throw new SecurityException("Node is Directory");
return nodeRank;
return node.getRank();
}
@Deprecated
public int getRankUnsafe() {
return nodeRank;
return node.getRank();
}
public void setRank(int rank) {
if(isDir())
throw new SecurityException("Node is Directory");
this.nodeRank = rank;
node.setRank(rank);
}
public SchematicType getSchemtype() {
if(isDir())
throw new SecurityException("Is Directory");
return nodeType;
return node.getSchemtype();
}
public void setSchemtype(SchematicType type) {
if(isDir())
throw new SecurityException("Is Directory");
this.nodeType = type;
updateDB();
node.setSchemtype(type);
}
public boolean replaceColor() {
return replaceColor;
return node.replaceColor();
}
public void setReplaceColor(boolean replaceColor) {
if(isDir())
throw new SecurityException("Is Directory");
this.replaceColor = replaceColor;
updateDB();
node.setReplaceColor(replaceColor);
}
public boolean allowReplay() {
return allowReplay;
return node.allowReplay();
}
public void setAllowReplay(boolean allowReplay) {
if(isDir())
throw new SecurityException("Is Directory");
this.allowReplay = allowReplay;
updateDB();
node.setAllowReplay(allowReplay);
}
public SchematicNode getParentNode() {
if(parentNode == null) return null;
return SchematicNode.getSchematicNode(parentNode);
return node.getParent() == de.steamwar.sql.v2.SchematicNode.ROOT ? null : new SchematicNode(node.getParent());
}
public int getElo(int season) {
return SchemElo.getElo(this, season);
return node.getElo(season);
}
public boolean accessibleByUser(int user) {
return NodeMember.getNodeMember(nodeId, user) != null;
return node.accessibleByUser(user);
}
public Set<NodeMember> getMembers() {
return NodeMember.getNodeMembers(nodeId);
return node.getMembers();
}
public Timestamp getLastUpdate() {
return lastUpdate;
}
private void updateDB() {
this.lastUpdate = Timestamp.from(Instant.now());
update.update(nodeId, nodeOwner, nodeName, parentNode, nodeItem, nodeType, lastUpdate, nodeRank, replaceColor, allowReplay, nodeFormat);
this.brCache.clear();
TAB_CACHE.clear();
return node.getLastUpdate();
}
public void delete() {
delete.update(nodeId);
node.delete();
}
@Override
public int hashCode() {
return nodeId;
return node.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof SchematicNode))
return false;
return ((SchematicNode) obj).getId() == nodeId;
return node.equals(obj);
}
public String generateBreadcrumbs(SteamwarUser user) {
return brCache.computeIfAbsent(user.getId(), integer -> generateBreadcrumbs("/", user));
return node.generateBreadcrumbs(user);
}
public String generateBreadcrumbs(String split, SteamwarUser user) {
StringBuilder builder = new StringBuilder(getName());
SchematicNode currentNode = this;
if (currentNode.isDir()) builder.append("/");
final Set<NodeMember> nodeMembers = NodeMember.getSchematics(user.getId());
AtomicInteger i = new AtomicInteger();
i.set(currentNode.getId());
while (currentNode.getParentNode() != null && nodeMembers.stream().noneMatch(nodeMember -> nodeMember.getNode() == i.get())) {
currentNode = currentNode.getParentNode();
i.set(currentNode.getId());
builder.insert(0, split)
.insert(0, currentNode.getName());
}
return builder.toString();
return node.generateBreadcrumbs(split, user);
}
private static final List<String> FORBIDDEN_NAMES = Collections.unmodifiableList(Arrays.asList("public"));
public static boolean invalidSchemName(String[] layers) {
for (String layer : layers) {
if (layer.isEmpty()) {
return true;
}
if (layer.contains("/") ||
layer.contains("\\") ||
layer.contains("<") ||
layer.contains(">") ||
layer.contains("^") ||
layer.contains("°") ||
layer.contains("'") ||
layer.contains("\"") ||
layer.contains(" ")) {
return true;
}
if(FORBIDDEN_NAMES.contains(layer.toLowerCase())) {
return true;
}
}
return false;
return de.steamwar.sql.v2.SchematicNode.invalidSchemName(layers);
}
public static List<String> getNodeTabcomplete(SteamwarUser user, String s) {
boolean sws = s.startsWith("/");
if (sws) {
s = s.substring(1);
}
int index = s.lastIndexOf("/");
String cacheKey = index == -1 ? "" : s.substring(0, index);
if(TAB_CACHE.containsKey(user.getId()) && TAB_CACHE.get(user.getId()).containsKey(cacheKey)) {
return new ArrayList<>(TAB_CACHE.get(user.getId()).get(cacheKey));
}
List<String> list = new ArrayList<>();
if (s.contains("/")) {
String preTab = s.substring(0, s.lastIndexOf("/") + 1);
SchematicNode pa = SchematicNode.getNodeFromPath(user, preTab);
if (pa == null) return Collections.emptyList();
List<SchematicNode> nodes = SchematicNode.getSchematicNodeInNode(pa);
nodes.forEach(node -> list.add((sws ? "/" : "") + node.generateBreadcrumbs(user)));
} else {
List<SchematicNode> nodes = SchematicNode.getSchematicsAccessibleByUser(user.getId(), 0);
nodes.forEach(node -> list.add((sws ? "/" : "") + node.getName() + (node.isDir() ? "/" : "")));
}
list.remove("//copy");
TAB_CACHE.computeIfAbsent(user.getId(), integer -> new HashMap<>()).putIfAbsent(cacheKey, list);
return list;
}
private static void rootWarning() {
ByteArrayOutputStream stacktraceOutput = new ByteArrayOutputStream();
new Throwable().printStackTrace(new PrintStream(stacktraceOutput));
SWException.log("PERFORMANCE!!! Getting all/weird subset of schematic nodes with parent NULL", stacktraceOutput.toString());
return de.steamwar.sql.v2.SchematicNode.getNodeTabcomplete(user, s);
}
}

Datei anzeigen

@ -0,0 +1,482 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql.v2;
import de.steamwar.sql.*;
import de.steamwar.sql.internal.*;
import lombok.AccessLevel;
import lombok.Setter;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class SchematicNode {
static {
new SqlTypeMapper<>(SchematicNode.class, null, (rs, identifier) -> { throw new SecurityException("SchematicNode cannot be used as type (recursive select)"); }, (st, index, value) -> st.setInt(index, value.nodeId));
}
private static final Map<Integer, Map<String, List<String>>> TAB_CACHE = new HashMap<>();
public static void clear() {
TAB_CACHE.clear();
}
private static final String[] fields = {"NodeId", "NodeOwner", "NodeName", "ParentNode", "LastUpdate", "NodeItem", "NodeType", "NodeRank", "ReplaceColor", "AllowReplay", "NodeFormat"};
private static String nodeSelectCreator(String itemPrefix) {
return "SELECT " + Arrays.stream(fields).map(s -> itemPrefix + s).collect(Collectors.joining(", ")) + " FROM SchematicNode ";
}
public static final SchematicNode ROOT = new SchematicNode(0, 0, "ROOT", 0, Timestamp.from(Instant.now()), "", SchematicType.Normal, 0, false, false, false);
private static final Table<SchematicNode> table = new Table<>(SchematicNode.class);
private static final Statement create = table.insertFields(true, "NodeOwner", "NodeName", "ParentNode", "NodeItem", "NodeType");
private static final Statement update = table.insertAll();
private static final Statement delete = table.delete(Table.PRIMARY);
private static final SelectStatement<SchematicNode> byId = table.select(Table.PRIMARY);
private static final SelectStatement<SchematicNode> byOwnerNameParent = table.select("OwnerNameParent");
private static final SelectStatement<SchematicNode> byParent = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE ParentNode = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> dirsByParent = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE ParentNode = ? AND NodeType is NULL ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byParentName = table.selectFields("NodeName", "ParentNode");
private static final SelectStatement<SchematicNode> accessibleByUserTypeParent = new SelectStatement<>(table, "WITH RECURSIVE RSNB AS (WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN WHERE NodeType = ? UNION " + nodeSelectCreator("SN.") + "AS SN, RSNB WHERE SN.NodeId = RSNB.ParentNode)SELECT * FROM RSNB WHERE ParentNode = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> accessibleByUserType = new SelectStatement<>(table, "WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN WHERE NodeType = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byOwnerType = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE NodeOwner = ? AND NodeType = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byType = new SelectStatement<>(table, nodeSelectCreator("") + "WHERE NodeType = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> accessibleByUser = new SelectStatement<>(table, nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) AND ((s.NodeOwner = ? AND s.ParentNode IS NULL) OR NOT s.NodeOwner = ?) GROUP BY s.NodeId ORDER BY s.NodeName");
private static final Statement schematicAccessibleForUser = new Statement("WITH RECURSIVE RSN AS (" + nodeSelectCreator("") + "WHERE NodeId = ? UNION " + nodeSelectCreator("SN.") + "SN, RSN WHERE RSN.ParentNode = SN.NodeId) SELECT COUNT(RSN.NodeId) AS `Accessible` FROM RSN LEFT Join NodeMember NM On NM.NodeId = RSN.NodeId WHERE NodeOwner = ? OR UserId = ? LIMIT 1");
private static final SelectStatement<SchematicNode> allAccessibleByUser = new SelectStatement<>(table, "WITH RECURSIVE RSN as (" + nodeSelectCreator("s.") + "s LEFT JOIN NodeMember n ON s.NodeId = n.NodeId WHERE (s.NodeOwner = ? OR n.UserId = ?) GROUP BY s.NodeId UNION " + nodeSelectCreator("SN.") + "AS SN, RSN WHERE SN.ParentNode = RSN.NodeId) SELECT * FROM RSN ORDER BY NodeName");
private static final SelectStatement<SchematicNode> allParentsOfNode = new SelectStatement<>(table, "WITH RECURSIVE RSN AS (" + nodeSelectCreator("") + "WHERE NodeId = ? UNION " + nodeSelectCreator("SN.") + "SN, RSN WHERE RSN.ParentNode = SN.NodeId) SELECT * FROM RSN ORDER BY NodeName");
@Field(keys = {Table.PRIMARY}, autoincrement = true)
private final int nodeId;
@Field(keys = {"OwnerNameParent"})
private final int nodeOwner;
@Field(keys = {"OwnerNameParent"})
private String nodeName;
@Field(keys = {"OwnerNameParent"})
private int parentNode;
@Field(def = "CURRENT_TIMESTAMP")
private Timestamp lastUpdate;
@Field(def = "''")
private String nodeItem;
@Field(def = "'normal'", nullable = true)
private SchematicType nodeType;
@Field(def = "0")
private int nodeRank;
@Field(def = "1")
private boolean replaceColor;
@Field(def = "1")
private boolean allowReplay;
@Setter(AccessLevel.PACKAGE)
@Field(def = "1")
private boolean nodeFormat;
private final Map<Integer, String> brCache = new HashMap<>();
public SchematicNode(
int nodeId,
int nodeOwner,
String nodeName,
int parentNode,
Timestamp lastUpdate,
String nodeItem,
SchematicType nodeType,
int nodeRank,
boolean replaceColor,
boolean allowReplay,
boolean nodeFormat
) {
this.nodeId = nodeId;
this.nodeOwner = nodeOwner;
this.nodeName = nodeName;
this.parentNode = parentNode;
this.nodeItem = nodeItem;
this.nodeType = nodeType;
this.lastUpdate = lastUpdate;
this.nodeRank = nodeRank;
this.replaceColor = replaceColor;
this.allowReplay = allowReplay;
this.nodeFormat = nodeFormat;
}
public static SchematicNode createSchematic(SteamwarUser owner, String name, int parent) {
return createSchematicNode(owner, name, parent, SchematicType.Normal.toDB(), "");
}
public static SchematicNode createSchematicDirectory(SteamwarUser owner, String name, int parent) {
return createSchematicNode(owner, name, parent, null, "");
}
public static SchematicNode createSchematicNode(SteamwarUser owner, String name, int parent, String type, String item) {
int nodeId = create.insertGetKey(owner, name, parent, type, item);
return getSchematicNode(nodeId);
}
public static Optional<SchematicNode> getSchematicNode(SteamwarUser owner, String name, SchematicNode parent) {
return getSchematicNode(owner, name, parent.getId());
}
public static Optional<SchematicNode> getSchematicNode(SteamwarUser owner, String name, int parent) {
return Optional.ofNullable(byOwnerNameParent.select(owner, name, parent));
}
public static List<SchematicNode> getSchematicNodeInNode(SchematicNode parent) {
if(parent.equals(ROOT)) {
rootWarning();
}
return byParent.listSelect(parent);
}
public static List<SchematicNode> getSchematicDirectoryInNode(SchematicNode parent) {
if(parent.equals(ROOT)) {
rootWarning();
}
return dirsByParent.listSelect(parent);
}
public static Optional<SchematicNode> getSchematicNode(String name, SchematicNode parent) {
if(parent.equals(ROOT)) {
rootWarning();
}
return Optional.ofNullable(byParentName.select(name, parent));
}
public static SchematicNode getSchematicNode(int id) {
if(id == 0) return ROOT;
return Optional.ofNullable(byId.select(id)).orElseThrow(() -> new IllegalStateException("Schematic node " + id + " does not exist"));
}
public static List<SchematicNode> getAccessibleSchematicsOfTypeInParent(SteamwarUser owner, String schemType, SchematicNode parent) {
return accessibleByUserTypeParent.listSelect(owner, owner, schemType, parent);
}
public static List<SchematicNode> getAllAccessibleSchematicsOfType(SteamwarUser user, SchematicType schemType) {
return accessibleByUserType.listSelect(user, user, schemType);
}
public static List<SchematicNode> getAllSchematicsOfType(SteamwarUser owner, SchematicType schemType) {
return byOwnerType.listSelect(owner, schemType);
}
public static List<SchematicNode> getAllSchematicsOfType(SchematicType schemType) {
return byType.listSelect(schemType);
}
public static List<SchematicNode> deepGet(SchematicNode parent, Predicate<SchematicNode> filter) {
List<SchematicNode> finalList = new ArrayList<>();
List<SchematicNode> nodes = SchematicNode.getSchematicNodeInNode(parent);
nodes.forEach(node -> {
if (node.isDir()) {
finalList.addAll(deepGet(node, filter));
} else {
if (filter.test(node))
finalList.add(node);
}
});
return finalList;
}
public static List<SchematicNode> getSchematicsAccessibleByUser(SteamwarUser user, SchematicNode parent) {
if (parent.equals(ROOT)) {
return accessibleByUser.listSelect(user, user, user, user);
}
if(Boolean.TRUE.equals(schematicAccessibleForUser.select(rs -> {
rs.next();
return rs.getBoolean("Accessible");
}, parent, user, user)))
return getSchematicNodeInNode(parent);
return Collections.emptyList();
}
public static List<SchematicNode> getAllSchematicsAccessibleByUser(SteamwarUser user) {
return allAccessibleByUser.listSelect(user, user);
}
public static List<SchematicNode> getAllParentsOfNode(SchematicNode node) {
return allParentsOfNode.listSelect(node);
}
public static Optional<SchematicNode> getNodeFromPath(SteamwarUser user, String s) {
if (s.startsWith("/")) {
s = s.substring(1);
}
if (s.isEmpty()) {
return Optional.empty();
}
if (s.contains("/")) {
String[] layers = s.split("/");
SchematicNode currentNode = null;
for (int i = 0; i < layers.length; i++) {
int finalI = i;
Optional<SchematicNode> node;
if (currentNode == null) {
node = SchematicNode.getSchematicsAccessibleByUser(user, ROOT).stream().filter(node1 -> node1.getName().equals(layers[finalI])).findAny();
} else {
node = SchematicNode.getSchematicNode(layers[i], currentNode);
}
if (!node.isPresent()) {
return Optional.empty();
} else {
currentNode = node.get();
if (!currentNode.isDir() && i != layers.length - 1) {
return Optional.empty();
}
}
}
return Optional.ofNullable(currentNode);
} else {
String finalS = s;
return SchematicNode.getSchematicsAccessibleByUser(user, ROOT).stream().filter(node1 -> node1.getName().equals(finalS)).findAny();
}
}
public static List<SchematicNode> filterSchems(SteamwarUser user, Predicate<SchematicNode> filter) {
List<SchematicNode> finalList = new ArrayList<>();
List<SchematicNode> nodes = getSchematicsAccessibleByUser(user, ROOT);
nodes.forEach(node -> {
if (node.isDir()) {
finalList.addAll(deepGet(node, filter));
} else {
if (filter.test(node))
finalList.add(node);
}
});
return finalList;
}
public int getId() {
return nodeId;
}
public SteamwarUser getOwner() {
return SteamwarUser.get(nodeOwner);
}
public String getName() {
return nodeName;
}
public void setName(String name) {
this.nodeName = name;
updateDB();
}
public SchematicNode getParent() {
return SchematicNode.getSchematicNode(parentNode);
}
public void setParent(SchematicNode parent) {
this.parentNode = parent.nodeId;
updateDB();
}
public String getItem() {
if (nodeItem.isEmpty()) {
return isDir() ? "CHEST" : "CAULDRON_ITEM";
}
return nodeItem;
}
public void setItem(String item) {
this.nodeItem = item;
updateDB();
}
public boolean isDir() {
return nodeType == null;
}
public boolean getSchemFormat() {
throwIfDir();
return nodeFormat;
}
public int getRank() {
throwIfDir();
return nodeRank;
}
public void setRank(int rank) {
throwIfDir();
this.nodeRank = rank;
}
public SchematicType getSchemtype() {
throwIfDir();
return nodeType;
}
public void setSchemtype(SchematicType type) {
throwIfDir();
this.nodeType = type;
updateDB();
}
public boolean replaceColor() {
return replaceColor;
}
public void setReplaceColor(boolean replaceColor) {
throwIfDir();
this.replaceColor = replaceColor;
updateDB();
}
public boolean allowReplay() {
return allowReplay;
}
public void setAllowReplay(boolean allowReplay) {
throwIfDir();
this.allowReplay = allowReplay;
updateDB();
}
public int getElo(int season) {
return SchemElo.getElo(this, season);
}
public boolean accessibleByUser(int user) {
return NodeMember.getNodeMember(nodeId, user) != null;
}
public Set<NodeMember> getMembers() {
return NodeMember.getNodeMembers(nodeId);
}
public Timestamp getLastUpdate() {
return lastUpdate;
}
private void updateDB() {
this.lastUpdate = Timestamp.from(Instant.now());
update.update(nodeId, nodeOwner, nodeName, parentNode, nodeItem, nodeType, lastUpdate, nodeRank, replaceColor, allowReplay, nodeFormat);
this.brCache.clear();
TAB_CACHE.clear();
}
public void delete() {
delete.update(nodeId);
}
@Override
public int hashCode() {
return nodeId;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof SchematicNode))
return false;
return ((SchematicNode) obj).getId() == nodeId;
}
public String generateBreadcrumbs(SteamwarUser user) {
return brCache.computeIfAbsent(user.getId(), integer -> generateBreadcrumbs("/", user));
}
public String generateBreadcrumbs(String split, SteamwarUser user) {
StringBuilder builder = new StringBuilder(getName());
SchematicNode currentNode = this;
if (currentNode.isDir()) builder.append("/");
final Set<NodeMember> nodeMembers = NodeMember.getSchematics(user.getId());
AtomicInteger i = new AtomicInteger();
i.set(currentNode.getId());
while (!currentNode.getParent().equals(ROOT) && nodeMembers.stream().noneMatch(nodeMember -> nodeMember.getNode() == i.get())) {
currentNode = currentNode.getParent();
i.set(currentNode.getId());
builder.insert(0, split)
.insert(0, currentNode.getName());
}
return builder.toString();
}
private static final List<String> FORBIDDEN_NAMES = Collections.unmodifiableList(Arrays.asList("public"));
public static boolean invalidSchemName(String[] layers) {
for (String layer : layers) {
if (layer.isEmpty()) {
return true;
}
if (layer.contains("/") ||
layer.contains("\\") ||
layer.contains("<") ||
layer.contains(">") ||
layer.contains("^") ||
layer.contains("°") ||
layer.contains("'") ||
layer.contains("\"") ||
layer.contains(" ")) {
return true;
}
if(FORBIDDEN_NAMES.contains(layer.toLowerCase())) {
return true;
}
}
return false;
}
public static List<String> getNodeTabcomplete(SteamwarUser user, String s) {
boolean sws = s.startsWith("/");
if (sws) {
s = s.substring(1);
}
int index = s.lastIndexOf("/");
String cacheKey = index == -1 ? "" : s.substring(0, index);
if(TAB_CACHE.containsKey(user.getId()) && TAB_CACHE.get(user.getId()).containsKey(cacheKey)) {
return new ArrayList<>(TAB_CACHE.get(user.getId()).get(cacheKey));
}
List<String> list = new ArrayList<>();
if (s.contains("/")) {
String preTab = s.substring(0, s.lastIndexOf("/") + 1);
Optional<SchematicNode> pa = SchematicNode.getNodeFromPath(user, preTab);
if (!pa.isPresent()) return Collections.emptyList();
List<SchematicNode> nodes = pa.map(SchematicNode::getSchematicNodeInNode).orElseGet(Collections::emptyList);
nodes.forEach(node -> list.add((sws ? "/" : "") + node.generateBreadcrumbs(user)));
} else {
List<SchematicNode> nodes = SchematicNode.getSchematicsAccessibleByUser(user, ROOT);
nodes.forEach(node -> list.add((sws ? "/" : "") + node.getName() + (node.isDir() ? "/" : "")));
}
list.remove("//copy");
TAB_CACHE.computeIfAbsent(user.getId(), integer -> new HashMap<>()).putIfAbsent(cacheKey, list);
return list;
}
private static void rootWarning() {
ByteArrayOutputStream stacktraceOutput = new ByteArrayOutputStream();
new Throwable().printStackTrace(new PrintStream(stacktraceOutput));
SWException.log("PERFORMANCE!!! Getting all/weird subset of schematic nodes with parent NULL", stacktraceOutput.toString());
}
private void throwIfDir() {
if (isDir()) {
throw new SecurityException("Is Directory");
}
}
}