Compare commits
3 Commits
5aa8dce299
...
d2ab24ed64
Author | SHA1 | Date | |
---|---|---|---|
d2ab24ed64 | |||
10183ac56b | |||
8d358e694e |
17
discord-bot/events/MessageCreate.js
Normal file
17
discord-bot/events/MessageCreate.js
Normal file
@ -0,0 +1,17 @@
|
||||
const { Events } = require('discord.js');
|
||||
|
||||
module.exports = {
|
||||
name: Events.MessageCreate,
|
||||
async execute({ log }, message) {
|
||||
|
||||
if (message.channelId === process.env.MINECRAFT_CHANNEL_ID && !message.author.bot) {
|
||||
await fetch(process.env.WEB_HOST + '/api/minecraft/message/chattominecraft', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
content: message.content,
|
||||
discordId: message.author.id,
|
||||
}),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
const { EmbedBuilder } = require('discord.js');
|
||||
|
||||
const registerEvents = ({ createEmbed, client }) => {
|
||||
const registerEvents = ({ client }) => {
|
||||
|
||||
client.player.on('trackStart', (queue, track) => {
|
||||
|
||||
|
@ -4,6 +4,7 @@ const { Player } = require('discord-player');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const dotenv = require('dotenv');
|
||||
const express = require('express');
|
||||
|
||||
const createEmbed = require('./functions/createEmbed.js');
|
||||
dotenv.config();
|
||||
@ -15,11 +16,25 @@ const log = {
|
||||
};
|
||||
|
||||
// Register client and music events
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMembers] });
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] });
|
||||
client.player = new Player(client);
|
||||
|
||||
require('./functions/player.js').registerEvents({ client, createEmbed });
|
||||
|
||||
|
||||
// Express
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
const messageRoute = require('./routes/Message');
|
||||
|
||||
app.use('/minecraft', messageRoute);
|
||||
|
||||
app.listen('4000', () => {
|
||||
log.Info('Express app running');
|
||||
});
|
||||
|
||||
|
||||
// Command handling
|
||||
client.commands = new Collection();
|
||||
|
||||
@ -53,3 +68,5 @@ for (const file of eventFiles) {
|
||||
}
|
||||
|
||||
client.login(process.env.DISCORD_TOKEN);
|
||||
|
||||
module.exports.client = client;
|
||||
|
1448
discord-bot/package-lock.json
generated
1448
discord-bot/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -17,6 +17,8 @@
|
||||
"discord.js": "^14.7.1",
|
||||
"distube": "^4.0.4",
|
||||
"dotenv": "^16.0.3",
|
||||
"eslint": "^8.29.0"
|
||||
"eslint": "^8.29.0",
|
||||
"express": "^4.18.2",
|
||||
"ytdl-core": "^4.11.4"
|
||||
}
|
||||
}
|
||||
|
38
discord-bot/routes/Message.js
Normal file
38
discord-bot/routes/Message.js
Normal file
@ -0,0 +1,38 @@
|
||||
const { WebhookClient, EmbedBuilder } = require('discord.js');
|
||||
const express = require('express');
|
||||
|
||||
const router = express.Router();
|
||||
const webhookClient = new WebhookClient({ url: process.env.MINECRAFT_WEBHOOK_URL });
|
||||
|
||||
router.post('/sendchatmessage', (req, res) => {
|
||||
const { content, username, avatarURL } = req.body;
|
||||
|
||||
if (!username || !content || !avatarURL) return res.status(400).send({ error: 'Content, username and avatar_url are required' });
|
||||
|
||||
webhookClient.send({
|
||||
content: content,
|
||||
username: username,
|
||||
avatarURL: avatarURL,
|
||||
});
|
||||
|
||||
res.send({ data: 'Test data' });
|
||||
});
|
||||
|
||||
router.post('/sendgamemessage', (req, res) => {
|
||||
const { content, avatarURL } = req.body;
|
||||
|
||||
if (!content || !avatarURL) return res.status(400).send({ error: 'Content, username and avatar_url are required' });
|
||||
|
||||
const messageEmbed = new EmbedBuilder()
|
||||
.setColor(process.env.EMBED_COLOR)
|
||||
.setAuthor({ name: content, iconURL: avatarURL });
|
||||
|
||||
webhookClient.send({
|
||||
embeds: [messageEmbed],
|
||||
username: 'Server',
|
||||
});
|
||||
|
||||
res.send({ data: 'Test data' });
|
||||
});
|
||||
|
||||
module.exports = router;
|
@ -24,7 +24,6 @@ loom {
|
||||
mods {
|
||||
"polarcraft-mod" {
|
||||
sourceSet sourceSets.main
|
||||
sourceSet sourceSets.client
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +0,0 @@
|
||||
package com.xeovalyte.polarcraft;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
|
||||
public class ExampleModClient implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
// This entrypoint is suitable for setting up client-specific logic, such as rendering.
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package com.xeovalyte.polarcraft.mixin.client;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(MinecraftClient.class)
|
||||
public class ExampleClientMixin {
|
||||
@Inject(at = @At("HEAD"), method = "run")
|
||||
private void run(CallbackInfo info) {
|
||||
// This code is injected into the start of MinecraftClient.run()V
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "com.xeovalyte.polarcraft.mixin.client",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"client": [
|
||||
"ExampleClientMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
@ -1,33 +1,23 @@
|
||||
package com.xeovalyte.polarcraft;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import com.xeovalyte.polarcraft.util.messageFunctions;
|
||||
import com.xeovalyte.polarcraft.util.verifyFunction;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.network.message.SignedMessage;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.File;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import net.fabricmc.fabric.api.message.v1.ServerMessageEvents;
|
||||
|
||||
public class PolarcraftMod implements ModInitializer {
|
||||
@ -39,8 +29,9 @@ public class PolarcraftMod implements ModInitializer {
|
||||
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||
private static final File CONFIG_FILE = new File(FabricLoader.getInstance().getConfigDir().toFile(), "polarcraft.json");
|
||||
|
||||
private String configWebhookUrl = "https://discordapp.com/api/webhooks/webhookid/webhooktoken";
|
||||
private String configVerifyUrl = "https://example.com/api/minecraft/verifyuuid";
|
||||
public static String configChatMessageUrl = "https://example.com/api/minecraft/message/chattodiscord";
|
||||
public static String configGameMessageUrl = "https://example.com/api/minecraft/message/gametodiscord";
|
||||
public static String configVerifyUrl = "https://example.com/api/minecraft/verifyuuid";
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
@ -51,15 +42,17 @@ public class PolarcraftMod implements ModInitializer {
|
||||
|
||||
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
|
||||
ServerPlayerEntity player = (ServerPlayerEntity) handler.player;
|
||||
onPlayerJoin(player);
|
||||
|
||||
verifyFunction.onPlayerJoin(player);
|
||||
});
|
||||
|
||||
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
|
||||
ServerPlayerEntity player = (ServerPlayerEntity) handler.player;
|
||||
messageFunctions.sendGameMessage(player.getUuid(), player.getDisplayName().getString() + " left the game");
|
||||
});
|
||||
|
||||
ServerMessageEvents.CHAT_MESSAGE.register((message, sender, params) -> {
|
||||
onChatMessage(message, sender);
|
||||
});
|
||||
|
||||
ServerMessageEvents.GAME_MESSAGE.register((server, message, overlay) -> {
|
||||
onGameMessage(server, message);
|
||||
messageFunctions.sendChatMessage(message, sender);
|
||||
});
|
||||
}
|
||||
|
||||
@ -71,7 +64,8 @@ public class PolarcraftMod implements ModInitializer {
|
||||
|
||||
try {
|
||||
MyModConfig config = GSON.fromJson(FileUtils.readFileToString(CONFIG_FILE, StandardCharsets.UTF_8), MyModConfig.class);
|
||||
configWebhookUrl = config.webhookUrl;
|
||||
configChatMessageUrl = config.chatMessageUrl;
|
||||
configGameMessageUrl = config.gameMessageUrl;
|
||||
configVerifyUrl = config.verifyUrl;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
@ -80,120 +74,21 @@ public class PolarcraftMod implements ModInitializer {
|
||||
|
||||
private void saveConfig() {
|
||||
try {
|
||||
FileUtils.writeStringToFile(CONFIG_FILE, GSON.toJson(new MyModConfig(configWebhookUrl, configVerifyUrl)), StandardCharsets.UTF_8);
|
||||
FileUtils.writeStringToFile(CONFIG_FILE, GSON.toJson(new MyModConfig(configChatMessageUrl, configGameMessageUrl,configVerifyUrl)), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MyModConfig {
|
||||
public String webhookUrl;
|
||||
public String chatMessageUrl;
|
||||
public String gameMessageUrl;
|
||||
public String verifyUrl;
|
||||
|
||||
public MyModConfig(String webhookUrl, String verifyUrl) {
|
||||
this.webhookUrl = webhookUrl;
|
||||
public MyModConfig(String chatMessageUrl, String gameMessageUrl,String verifyUrl) {
|
||||
this.chatMessageUrl = chatMessageUrl;
|
||||
this.gameMessageUrl = gameMessageUrl;
|
||||
this.verifyUrl = verifyUrl;
|
||||
}
|
||||
}
|
||||
|
||||
private void onChatMessage( SignedMessage message, ServerPlayerEntity sender) {
|
||||
try {
|
||||
// Create a URL object for the server endpoint
|
||||
URL url = new URL(configWebhookUrl);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setDoOutput(true);
|
||||
|
||||
String requestBody = "{\"content\":\"" + sender.getName().getString() + " > "+ message.getSignedContent() + "\"}";
|
||||
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
outputStream.write(requestBody.getBytes());
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String line;
|
||||
StringBuilder response = new StringBuilder();
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void onGameMessage( MinecraftServer server, Text message) {
|
||||
try {
|
||||
// Create a URL object for the server endpoint
|
||||
URL url = new URL(configWebhookUrl);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setDoOutput(true);
|
||||
|
||||
String requestBody = "{\"content\":\"" + "**" + message.getString() + "**" + "\"}";
|
||||
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
outputStream.write(requestBody.getBytes());
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String line;
|
||||
StringBuilder response = new StringBuilder();
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void onPlayerJoin(ServerPlayerEntity player) {
|
||||
UUID uuid = player.getUuid();
|
||||
|
||||
try {
|
||||
URL url = new URL(configVerifyUrl);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setDoOutput(true);
|
||||
|
||||
String requestBody = "{\"uuid\":\"" + uuid + "\"}";
|
||||
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
outputStream.write(requestBody.getBytes());
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String line;
|
||||
StringBuilder response = new StringBuilder();
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
reader.close();
|
||||
|
||||
Gson gson = new Gson();
|
||||
JsonElement element = gson.fromJson(response.toString(), JsonElement.class);
|
||||
JsonObject jsonResponse = element.getAsJsonObject();
|
||||
|
||||
boolean verified = jsonResponse.get("verified").getAsBoolean();
|
||||
|
||||
if (!verified) {
|
||||
int code = jsonResponse.get("code").getAsInt();
|
||||
|
||||
player.networkHandler.disconnect(Text.literal("Whitelist yourself by using this code: " + code));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
player.networkHandler.disconnect(Text.literal("There was an error while verifing your account"));
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package com.xeovalyte.polarcraft.mixin;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public class ExampleMixin {
|
||||
@Inject(at = @At("HEAD"), method = "loadWorld")
|
||||
private void init(CallbackInfo info) {
|
||||
// This code is injected into the start of MinecraftServer.loadWorld()V
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.xeovalyte.polarcraft.mixin;
|
||||
|
||||
import com.xeovalyte.polarcraft.util.messageFunctions;
|
||||
import net.minecraft.advancement.Advancement;
|
||||
import net.minecraft.advancement.PlayerAdvancementTracker;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Mixin(PlayerAdvancementTracker.class)
|
||||
public class MixinPlayerAdvancementTracker {
|
||||
@Shadow
|
||||
private ServerPlayerEntity owner;
|
||||
|
||||
@Inject(method = "grantCriterion",
|
||||
at = @At(
|
||||
target = "Lnet/minecraft/server/PlayerManager;broadcast(Lnet/minecraft/text/Text;Z)V",
|
||||
value = "INVOKE"
|
||||
)
|
||||
)
|
||||
|
||||
private void grantCriterion(Advancement advancement, String criterionName, CallbackInfoReturnable<Boolean> cir) {
|
||||
// messageFunctions.sendGameMessage(owner.getUuid(), " has completed the challenge [" + Objects.requireNonNull(advancement.getDisplay()).getTitle().getString() + "]");
|
||||
messageFunctions.sendGameMessage(owner.getUuid(), owner.getDisplayName().getString() + " has completed the advancement [" + Objects.requireNonNull(advancement.getDisplay()).getTitle().getString() + "]");
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.xeovalyte.polarcraft.mixin;
|
||||
|
||||
import com.xeovalyte.polarcraft.util.messageFunctions;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
@Mixin(ServerPlayerEntity.class)
|
||||
public class MixinPlayerEntity {
|
||||
@Inject(method = "onDeath",
|
||||
at = @At(
|
||||
target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;sendPacket(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/PacketCallbacks;)V",
|
||||
value = "INVOKE",
|
||||
ordinal = 0),
|
||||
locals = LocalCapture.CAPTURE_FAILSOFT
|
||||
)
|
||||
private void onDeath(DamageSource damageSource, CallbackInfo ci, boolean bl, Text text){
|
||||
ServerPlayerEntity serverPlayerEntity = (ServerPlayerEntity) (Object) this;
|
||||
|
||||
messageFunctions.sendGameMessage(serverPlayerEntity.getUuid(), text.getString());
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package com.xeovalyte.polarcraft.util;
|
||||
|
||||
import com.xeovalyte.polarcraft.PolarcraftMod;
|
||||
|
||||
import net.minecraft.network.message.SignedMessage;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.UUID;
|
||||
|
||||
public class messageFunctions {
|
||||
public static void sendGameMessage(UUID uuid, String message) {
|
||||
try {
|
||||
// Create a URL object for the server endpoint
|
||||
URL url = new URL(PolarcraftMod.configGameMessageUrl);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setDoOutput(true);
|
||||
|
||||
String requestBody = "{\"content\":\"" + message + "\", \"uuid\":\"" + uuid + "\"}";
|
||||
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
outputStream.write(requestBody.getBytes());
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String line;
|
||||
StringBuilder response = new StringBuilder();
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendChatMessage( SignedMessage message, ServerPlayerEntity sender) {
|
||||
try {
|
||||
// Create a URL object for the server endpoint
|
||||
URL url = new URL(PolarcraftMod.configChatMessageUrl);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setDoOutput(true);
|
||||
|
||||
String requestBody = "{\"content\":\"" + message.getSignedContent() + "\", \"uuid\":\"" + sender.getUuid() + "\"}";
|
||||
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
outputStream.write(requestBody.getBytes());
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String line;
|
||||
StringBuilder response = new StringBuilder();
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.xeovalyte.polarcraft.util;
|
||||
|
||||
import com.xeovalyte.polarcraft.PolarcraftMod;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public class verifyFunction {
|
||||
public static void onPlayerJoin(ServerPlayerEntity player) {
|
||||
UUID uuid = player.getUuid();
|
||||
|
||||
try {
|
||||
URL url = new URL(PolarcraftMod.configVerifyUrl);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setDoOutput(true);
|
||||
|
||||
String requestBody = "{\"uuid\":\"" + uuid + "\"}";
|
||||
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
outputStream.write(requestBody.getBytes());
|
||||
outputStream.flush();
|
||||
outputStream.close();
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String line;
|
||||
StringBuilder response = new StringBuilder();
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
reader.close();
|
||||
|
||||
Gson gson = new Gson();
|
||||
JsonElement element = gson.fromJson(response.toString(), JsonElement.class);
|
||||
JsonObject jsonResponse = element.getAsJsonObject();
|
||||
|
||||
boolean verified = jsonResponse.get("verified").getAsBoolean();
|
||||
|
||||
if (!verified) {
|
||||
int code = jsonResponse.get("code").getAsInt();
|
||||
|
||||
player.networkHandler.disconnect(Text.literal("Whitelist yourself by using this code: " + code));
|
||||
} else {
|
||||
messageFunctions.sendGameMessage(player.getUuid(), player.getDisplayName().getString() + " joined the game");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
player.networkHandler.disconnect(Text.literal("There was an error while verifing your account"));
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -13,18 +13,14 @@
|
||||
},
|
||||
"license": "CC0-1.0",
|
||||
"icon": "assets/polarcraft-mod/icon.png",
|
||||
"environment": "*",
|
||||
"environment": "server",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"com.xeovalyte.polarcraft.PolarcraftMod"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"polarcraft-mod.mixins.json",
|
||||
{
|
||||
"config": "polarcraft-mod.client.mixins.json",
|
||||
"environment": "client"
|
||||
}
|
||||
"polarcraft-mod.mixins.json"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.14.19",
|
||||
|
@ -3,7 +3,8 @@
|
||||
"package": "com.xeovalyte.polarcraft.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"mixins": [
|
||||
"ExampleMixin"
|
||||
"MixinPlayerAdvancementTracker",
|
||||
"MixinPlayerEntity"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": ["@nuxt/eslint-config"],
|
||||
"extends": ["@nuxt/eslint-config", "plugin:tailwindcss/recommended"],
|
||||
"rules": {
|
||||
"vue/max-attributes-per-line": ["error", {
|
||||
"singleline": {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="w-full h-screen overflow-y-auto">
|
||||
<div class="h-screen w-full overflow-y-auto">
|
||||
<NuxtLayout :name="layout" />
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="w-full text-primary flex items-center flex-col">
|
||||
<div class="flex w-full flex-col items-center text-primary">
|
||||
<div v-if="!user.minecraft.uuid" class="flex flex-col items-center">
|
||||
<p class="max-w-xl mb-10 sm:text-base text-sm">
|
||||
<p class="mb-10 max-w-xl text-sm sm:text-base">
|
||||
Je bent momenteel niet gewhitelist. Om toegang te krijgen tot de Minecraft server moet je in Minecraft naar de
|
||||
server met het ip <span class="highlight">play.polarcraft.xeovalyte.com</span> gaan. Vervolgens krijg je een code
|
||||
te zien, vul deze code hieronder in.
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="bg-neutral-800 border-b border-b-gray-700 flex items-center px-5">
|
||||
<h1 class="text-primary text-2xl font-bold">Polarcraft</h1>
|
||||
<div class="flex items-center border-b border-b-gray-700 bg-neutral-800 px-5">
|
||||
<h1 class="text-2xl font-bold text-primary">Polarcraft</h1>
|
||||
<Button outline class="ml-auto" @click="logout">Logout</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="bg-neutral-800 text-gray-300 px-2 pt-5 pb-14 flex flex-col">
|
||||
<div class="flex flex-col bg-neutral-800 px-2 pb-14 pt-5 text-gray-300">
|
||||
<NuxtLink to="/" class="sidebar-item">
|
||||
<Icon size="1.5em" name="ph:house" class="mr-3" />
|
||||
Home
|
||||
|
180
web/components/team/Default.vue
Normal file
180
web/components/team/Default.vue
Normal file
@ -0,0 +1,180 @@
|
||||
<template>
|
||||
<Modal v-if="modalOpen" title="Invite team member" @close="modalOpen = false" @submit="modalOpen = false">
|
||||
<div>
|
||||
<h2 class="text-lg font-bold text-primary">Users</h2>
|
||||
<div class="h-48 space-y-3 overflow-y-auto">
|
||||
<div v-for="unaffiliatedUser in unaffilatedUsers" :key="unaffiliatedUser._id.toString()" class="flex items-center rounded bg-neutral-700 px-3 py-1 text-gray-200">
|
||||
{{ unaffiliatedUser.username }}
|
||||
<Button v-if="!unaffiliatedUser.teamInvites.includes(user.team.id)" class="ml-auto" @click="inviteUser(unaffiliatedUser)">Invite</Button>
|
||||
<Button v-else class="ml-auto" type="danger" @click="cancelInvite(unaffiliatedUser)">Cancel Invite</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
<Modal v-if="editTeamModal.open" title="Edit team" @close="editTeamModal.open = false" @submit="editTeam">
|
||||
<Input v-model:value="editTeamModal.name" background-class="bg-neutral-800" class="w-full max-w-sm">Naam / Prefix</Input>
|
||||
<Colorpicker v-model:value="editTeamModal.color" input-background-class="bg-neutral-800" class="w-full max-w-sm" />
|
||||
</Modal>
|
||||
<div class="mx-auto my-10 max-w-2xl">
|
||||
<h2 class="mb-2 text-xl font-bold text-primary">Team Information</h2>
|
||||
<div class="rounded border-[1px] border-primary px-5 py-2 text-primary">
|
||||
<table class="w-full table-auto">
|
||||
<tbody class="divide-y divide-gray-700">
|
||||
<tr>
|
||||
<td class="py-3">Name</td>
|
||||
<td class="font-bold">{{ team.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="py-3">Color</td>
|
||||
<td class="font-bold">{{ team.color }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="py-3">ID</td>
|
||||
<td class="font-bold">{{ team._id }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mb-10 mt-5 flex justify-center gap-x-3">
|
||||
<Button type="danger" @click="leaveTeam">Leave Team</Button>
|
||||
<Button @click="openTeamModal">Edit Team</Button>
|
||||
</div>
|
||||
<h2 class="mb-2 text-xl font-bold text-primary">Team Members</h2>
|
||||
<div class="space-y-5 rounded border-[1px] border-primary p-5 text-primary">
|
||||
<div v-for="teamMember in teamMembers" :key="teamMember._id" class="flex h-12 items-center rounded bg-neutral-800 px-5 font-bold text-gray-200">
|
||||
{{ teamMember.username }}
|
||||
<span v-if="teamMember.team.admin" class="ml-3 text-sm text-gray-400">Admin</span>
|
||||
<div v-if="user.team.admin" class="ml-auto">
|
||||
<Button v-if="!teamMember.team.admin && teamMember._id !== user._id" @click="promoteUser(teamMember)">Promote</Button>
|
||||
<Button v-if="teamMember.team.admin && teamMember._id !== user._id" @click="demoteUser(teamMember)">Demote</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="user.team.admin" class="rounded border-2 border-dashed border-neutral-500 bg-neutral-800 p-3 text-center font-bold text-gray-200 hover:cursor-pointer hover:bg-neutral-700" @click="modalOpen = true">
|
||||
Invite new member
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const user = useState('user');
|
||||
const { data: team } = await useFetch('/api/team');
|
||||
const { data: teamMembers } = await useFetch('/api/team/members');
|
||||
const { data: unaffilatedUsers } = await useFetch('/api/team/unaffiliated')
|
||||
|
||||
const modalOpen = ref(false)
|
||||
|
||||
const editTeamModal = ref({
|
||||
open: false,
|
||||
name: '',
|
||||
color: '',
|
||||
})
|
||||
|
||||
const openTeamModal = () => {
|
||||
editTeamModal.value.name = team.value.name
|
||||
editTeamModal.value.color = team.value.color
|
||||
editTeamModal.value.open = true
|
||||
}
|
||||
|
||||
const leaveTeam = async () => {
|
||||
try {
|
||||
await $fetch('/api/team/leave');
|
||||
|
||||
user.value.team = null;
|
||||
|
||||
useToast().success('Successfully left team')
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
useToast().error(e.statusMessage)
|
||||
}
|
||||
}
|
||||
|
||||
const editTeam = async () => {
|
||||
try {
|
||||
await $fetch('/api/team/edit', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
name: editTeamModal.value.name,
|
||||
color: editTeamModal.value.color,
|
||||
}
|
||||
});
|
||||
|
||||
team.value.name = editTeamModal.value.name
|
||||
team.value.color = editTeamModal.value.color
|
||||
|
||||
useToast().success('Successfully modified team')
|
||||
|
||||
editTeamModal.value.open = false
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
useToast().error(e.statusMessage)
|
||||
}
|
||||
}
|
||||
|
||||
const inviteUser = async (usr) => {
|
||||
try {
|
||||
await $fetch('/api/team/invite', {
|
||||
method: 'POST',
|
||||
body: { id: usr._id }
|
||||
});
|
||||
|
||||
usr.teamInvites.push(user.value.team.id);
|
||||
|
||||
useToast().success(`Successfully invited ${usr.username}`)
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
useToast().error(e.statusMessage)
|
||||
}
|
||||
}
|
||||
|
||||
const cancelInvite = async (usr) => {
|
||||
try {
|
||||
await $fetch('/api/team/cancelinvite', {
|
||||
method: 'POST',
|
||||
body: { id: usr._id }
|
||||
});
|
||||
|
||||
usr.teamInvites = usr.teamInvites.filter(a => a !== user.value.team.id);
|
||||
|
||||
useToast().success('Successfully cancelled invited')
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
useToast().error(e.statusMessage)
|
||||
}
|
||||
}
|
||||
|
||||
const promoteUser = async (usr) => {
|
||||
try {
|
||||
await $fetch('/api/team/promote', {
|
||||
method: 'POST',
|
||||
body: { userId: usr._id }
|
||||
});
|
||||
|
||||
usr.team.admin = true
|
||||
|
||||
console.log(usr)
|
||||
console.log(teamMembers)
|
||||
|
||||
useToast().success('Successfully promted user')
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
useToast().error(e.statusMessage)
|
||||
}
|
||||
}
|
||||
|
||||
const demoteUser = async (usr) => {
|
||||
try {
|
||||
await $fetch('/api/team/demote', {
|
||||
method: 'POST',
|
||||
body: { userId: usr._id }
|
||||
});
|
||||
|
||||
usr.team.admin = false
|
||||
|
||||
useToast().success('Successfully demoted user')
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
useToast().error(e.statusMessage)
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,20 +1,86 @@
|
||||
<template>
|
||||
<p class="text-gray-300 text-center my-10">
|
||||
<p class="my-10 text-center text-gray-300">
|
||||
Je zit momenteel niet in een team. Maak een team aan of wacht tot dat je geinvite wordt
|
||||
</p>
|
||||
<div class="flex w-full justify-center gap-10 mb-5">
|
||||
<span class="text-primary font-bold hover:cursor-pointer" :class="{'underline underline-offset-4': !createTeam}" @click="createTeam = false">Team Invites</span>
|
||||
<span class="text-primary font-bold hover:cursor-pointer" :class="{'underline underline-offset-4': createTeam}" @click="createTeam = true">Create Team</span>
|
||||
<div class="mb-5 flex w-full justify-center gap-10">
|
||||
<span
|
||||
class="font-bold text-primary hover:cursor-pointer" :class="{ 'underline underline-offset-4': !createTeam.show }"
|
||||
@click="createTeam.show = false"
|
||||
>
|
||||
Team Invites
|
||||
</span>
|
||||
<span
|
||||
class="font-bold text-primary hover:cursor-pointer" :class="{ 'underline underline-offset-4': createTeam.show }"
|
||||
@click="createTeam.show = true"
|
||||
>
|
||||
Create Team
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="!createTeam" class="text-center text-gray-300">
|
||||
You don't have any team invites
|
||||
<div v-if="!createTeam.show" class="text-center text-gray-300">
|
||||
<h2 v-if="!user.teamInvites.length">You don't have any team invites</h2>
|
||||
<div v-else class="mx-auto flex max-w-lg flex-col">
|
||||
<div v-for="team in filteredTeams" :key="team._id" class="flex items-center rounded bg-neutral-800 px-3 py-1 text-left" @click="acceptInvite(team)">
|
||||
<span>
|
||||
{{ team.name }}
|
||||
</span>
|
||||
<Button class="ml-auto">Accept</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="w-full flex flex-col items-center gap-5">
|
||||
<Input class="w-full max-w-sm">Naam / Prefix</Input>
|
||||
<Colorpicker class="w-full max-w-sm" />
|
||||
<div v-else class="flex w-full flex-col items-center gap-5">
|
||||
<Input v-model:value="createTeam.name" class="w-full max-w-sm">Naam / Prefix</Input>
|
||||
<Colorpicker v-model:value="createTeam.color" class="w-full max-w-sm" />
|
||||
<Button @click="handleCreateTeam">Create Team</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const createTeam = ref(false)
|
||||
const user = useState('user')
|
||||
|
||||
const teams = await $fetch('/api/team/all')
|
||||
|
||||
const filteredTeams = computed(() => {
|
||||
return teams.filter(a => user.value.teamInvites.includes(a._id));
|
||||
})
|
||||
|
||||
const createTeam = ref({
|
||||
show: false,
|
||||
name: '',
|
||||
color: '',
|
||||
})
|
||||
|
||||
const acceptInvite = async (team) => {
|
||||
try {
|
||||
const response = await $fetch('/api/team/acceptinvite', {
|
||||
method: 'POST',
|
||||
body: { teamId: team._id }
|
||||
})
|
||||
|
||||
console.log(response)
|
||||
|
||||
user.value.team = { id: response._id, admin: false }
|
||||
|
||||
useToast().success('Successfully joined team')
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
useToast().error(e.statusMessage)
|
||||
}
|
||||
}
|
||||
|
||||
const handleCreateTeam = async () => {
|
||||
try {
|
||||
const response = await $fetch('/api/team/create', {
|
||||
method: 'POST',
|
||||
body: { teamName: createTeam.value.name, teamColor: createTeam.value.color }
|
||||
})
|
||||
|
||||
user.value.team = { id: response.insertedId.toString(), admin: true }
|
||||
|
||||
useToast().success('Successfully created team')
|
||||
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
useToast().error(e.statusMessage)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div class="h-full bg-neutral-900">
|
||||
<div class="hidden sm:grid grid-cols-desktoplayout grid-rows-desktoplayout h-full">
|
||||
<div v-if="user" class="hidden h-full grid-cols-desktoplayout grid-rows-desktoplayout sm:grid">
|
||||
<LayoutNavbar class="col-span-2" />
|
||||
<LayoutSidebar v-if="user.minecraft.uuid" class="" />
|
||||
<div class="overflow-y-auto px-10 pt-5" :class="{ 'col-span-2': !user.minecraft.uuid }">
|
||||
<NuxtPage />
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:hidden h-full">
|
||||
<div class="overflow-y-auto px-2 py-2">
|
||||
<div v-if="user" class="h-full sm:hidden">
|
||||
<div class="overflow-y-auto p-2">
|
||||
<NuxtPage />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -13,11 +13,14 @@ export default defineNuxtConfig({
|
||||
runtimeConfig: {
|
||||
discordId: '',
|
||||
discordSecret: '',
|
||||
discordHost: '',
|
||||
jwtSecret: '',
|
||||
dbUrl: '',
|
||||
mineckerHost: '',
|
||||
mineckerApiKey: '',
|
||||
mincecraftContainer: 'mc-school',
|
||||
rconPassword: '',
|
||||
rconPort: '25575',
|
||||
rconHost: 'localhost',
|
||||
public: {
|
||||
redirectUrl: 'https://discord.com/api/oauth2/authorize?client_id=1052974736432443432&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth&response_type=code&scope=identify',
|
||||
}
|
||||
|
61
web/package-lock.json
generated
61
web/package-lock.json
generated
@ -11,6 +11,7 @@
|
||||
"@xeovalyte/nuxt-xvtoast": "^1.1.3",
|
||||
"@xeovalyte/nuxt-xvui": "git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"minecraft-server-util": "^5.4.2",
|
||||
"mongodb": "^5.3.0",
|
||||
"socket.io-client": "^4.6.1",
|
||||
"surrealdb.js": "^0.6.0"
|
||||
@ -24,6 +25,7 @@
|
||||
"@vueuse/core": "^10.1.0",
|
||||
"@vueuse/nuxt": "^10.1.0",
|
||||
"eslint": "^8.39.0",
|
||||
"eslint-plugin-tailwindcss": "^3.11.0",
|
||||
"nuxt": "^3.4.2",
|
||||
"nuxt-icon": "^0.3.3"
|
||||
}
|
||||
@ -3158,7 +3160,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@xeovalyte/nuxt-xvui": {
|
||||
"resolved": "git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git#e5bb7302f0626b39aa7b3a73bd4109b03702a9c7",
|
||||
"resolved": "git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git#53b253beae85b014c2556291aaa9f8f94fc765d5",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@nuxt/eslint-config": "^0.1.1",
|
||||
@ -5357,6 +5359,22 @@
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-tailwindcss": {
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-tailwindcss/-/eslint-plugin-tailwindcss-3.11.0.tgz",
|
||||
"integrity": "sha512-RaraOG4D6VXutKnoNvFQ4+frTWGJDKtezy1yCrGFS7Um1to/npDNdh2GL19IRoGB/eanbtwhxFXy+xyEw0grAg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fast-glob": "^3.2.5",
|
||||
"postcss": "^8.4.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.13.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"tailwindcss": "^3.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-vue": {
|
||||
"version": "9.11.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.11.0.tgz",
|
||||
@ -8092,6 +8110,22 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/minecraft-motd-util": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/minecraft-motd-util/-/minecraft-motd-util-1.1.12.tgz",
|
||||
"integrity": "sha512-5TuTRjrRupSTruea0nRC37r0FdhkS1O4wIJKAYfwJRCQd/X4Zyl/dVIs96h9UVW6N8jhIuz9pNkrDsqyN7VBdA=="
|
||||
},
|
||||
"node_modules/minecraft-server-util": {
|
||||
"version": "5.4.2",
|
||||
"resolved": "https://registry.npmjs.org/minecraft-server-util/-/minecraft-server-util-5.4.2.tgz",
|
||||
"integrity": "sha512-QjCM23pnXya+Fi2i3VxpQ5RS6luBA6Tkr0GAIG9dVhOrG5fBw10MVQyd13fJ4RquY3jQwNiHGX05G/0lnrQD5A==",
|
||||
"dependencies": {
|
||||
"minecraft-motd-util": "^1.1.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
@ -15804,7 +15838,7 @@
|
||||
}
|
||||
},
|
||||
"@xeovalyte/nuxt-xvui": {
|
||||
"version": "git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git#e5bb7302f0626b39aa7b3a73bd4109b03702a9c7",
|
||||
"version": "git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git#53b253beae85b014c2556291aaa9f8f94fc765d5",
|
||||
"from": "@xeovalyte/nuxt-xvui@git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git",
|
||||
"requires": {
|
||||
"@nuxt/eslint-config": "^0.1.1",
|
||||
@ -17427,6 +17461,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-plugin-tailwindcss": {
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-tailwindcss/-/eslint-plugin-tailwindcss-3.11.0.tgz",
|
||||
"integrity": "sha512-RaraOG4D6VXutKnoNvFQ4+frTWGJDKtezy1yCrGFS7Um1to/npDNdh2GL19IRoGB/eanbtwhxFXy+xyEw0grAg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-glob": "^3.2.5",
|
||||
"postcss": "^8.4.4"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-vue": {
|
||||
"version": "9.11.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.11.0.tgz",
|
||||
@ -19460,6 +19504,19 @@
|
||||
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
|
||||
"dev": true
|
||||
},
|
||||
"minecraft-motd-util": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/minecraft-motd-util/-/minecraft-motd-util-1.1.12.tgz",
|
||||
"integrity": "sha512-5TuTRjrRupSTruea0nRC37r0FdhkS1O4wIJKAYfwJRCQd/X4Zyl/dVIs96h9UVW6N8jhIuz9pNkrDsqyN7VBdA=="
|
||||
},
|
||||
"minecraft-server-util": {
|
||||
"version": "5.4.2",
|
||||
"resolved": "https://registry.npmjs.org/minecraft-server-util/-/minecraft-server-util-5.4.2.tgz",
|
||||
"integrity": "sha512-QjCM23pnXya+Fi2i3VxpQ5RS6luBA6Tkr0GAIG9dVhOrG5fBw10MVQyd13fJ4RquY3jQwNiHGX05G/0lnrQD5A==",
|
||||
"requires": {
|
||||
"minecraft-motd-util": "^1.1.9"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
|
@ -7,7 +7,8 @@
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare",
|
||||
"lint": "eslint ."
|
||||
"lint": "eslint .",
|
||||
"lint-fix": "eslint . --fix"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/devtools": "^0.4.2",
|
||||
@ -18,6 +19,7 @@
|
||||
"@vueuse/core": "^10.1.0",
|
||||
"@vueuse/nuxt": "^10.1.0",
|
||||
"eslint": "^8.39.0",
|
||||
"eslint-plugin-tailwindcss": "^3.11.0",
|
||||
"nuxt": "^3.4.2",
|
||||
"nuxt-icon": "^0.3.3"
|
||||
},
|
||||
@ -26,6 +28,7 @@
|
||||
"@xeovalyte/nuxt-xvtoast": "^1.1.3",
|
||||
"@xeovalyte/nuxt-xvui": "git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"minecraft-server-util": "^5.4.2",
|
||||
"mongodb": "^5.3.0",
|
||||
"socket.io-client": "^4.6.1",
|
||||
"surrealdb.js": "^0.6.0"
|
||||
|
@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<div class="w-full h-full text-primary flex flex-col">
|
||||
<h1 class="text-5xl font-bold text-center mt-20 mb-10">Welkom, {{ user.discord.username }}</h1>
|
||||
<div class="flex h-full w-full flex-col text-primary">
|
||||
<h1 class="mb-10 mt-20 text-center text-5xl font-bold">Welkom, {{ user.discord.username }}</h1>
|
||||
<Whitelist v-if="!user.minecraft.uuid" />
|
||||
<div v-else class="flex justify-center gap-4 flex-wrap max-w-3xl w-full">
|
||||
<div v-else class="flex w-full max-w-3xl flex-wrap justify-center gap-4">
|
||||
<img :src="'https://api.mineatar.io/face/' + user.minecraft.uuid + '?scale=16'" class="w-24 rounded shadow">
|
||||
<div class="rounded flex border-2 border-primary p-4 w-full max-w-md">
|
||||
<div class="flex w-full max-w-md rounded border-2 border-primary p-4">
|
||||
<ul class="my-auto">
|
||||
<li>Username: <b>{{ user.minecraft.username }}</b></li>
|
||||
<li>UUID: <b>{{ user.minecraft.uuid }}</b></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="w-full flex justify-center gap-4 mt-2">
|
||||
<div class="mt-2 flex w-full justify-center gap-4">
|
||||
<Button type="danger" @click="removeWhitelist">
|
||||
Remove from whitelist
|
||||
</Button>
|
||||
|
@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<div class="w-full h-screen text-primary bg-opacity-0 flex justify-center items-center flex-col px-2">
|
||||
<h1 class="sm:text-5xl text-3xl font-bold text-center mb-5">Polarcraft S5</h1>
|
||||
<p class="max-w-xl mb-10 sm:text-base text-sm">
|
||||
<b>Welkom bij Polarcraft seizoen 5!</b> Start door in te loggen met Discord en vervolgens je account te koppelen met Minecraft. Als je problemen hebt maak dan in Discord een ticket aan door het <span class="bg-black bg-opacity-50 px-2 rounded">/ticket</span> commando uit te voeren.
|
||||
<div class="flex h-screen w-full flex-col items-center justify-center bg-transparent px-2 text-primary">
|
||||
<h1 class="mb-5 text-center text-3xl font-bold sm:text-5xl">Polarcraft S5</h1>
|
||||
<p class="mb-10 max-w-xl text-sm sm:text-base">
|
||||
<b>Welkom bij Polarcraft seizoen 5!</b> Start door in te loggen met Discord en vervolgens je account te koppelen met Minecraft. Als je problemen hebt maak dan in Discord een ticket aan door het <span class="highlight">/ticket</span> commando uit te voeren.
|
||||
</p>
|
||||
<Button @click="navigateTo(config.public.redirectUrl, { external: true })">
|
||||
Log in with Discord
|
||||
<Icon size="1.6em" name="ic:baseline-discord" />
|
||||
</Button>
|
||||
|
||||
<div class="absolute top-0 left-0 -z-10 w-full h-screen overflow-hidden">
|
||||
<img src="../assets/pictures/diamond_wall.png" class="h-full w-full object-cover brightness-75 blur-[1px] scale-105">
|
||||
<div class="absolute left-0 top-0 -z-10 h-screen w-full overflow-hidden">
|
||||
<img src="../assets/pictures/diamond_wall.png" class="h-full w-full scale-105 object-cover blur-[1px] brightness-75">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,8 +1,17 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1 class="font-bold text-2xl text-primary">
|
||||
<h1 class="text-2xl font-bold text-primary">
|
||||
Team
|
||||
</h1>
|
||||
<TeamNone />
|
||||
<TeamNone v-if="!user.team" />
|
||||
<TeamDefault v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const user = useState('user')
|
||||
|
||||
definePageMeta({
|
||||
middleware: ["auth"]
|
||||
})
|
||||
</script>
|
||||
|
@ -37,7 +37,7 @@ export default defineEventHandler(async (event) => {
|
||||
},
|
||||
}
|
||||
|
||||
await coll.updateOne({ 'discord.id': userResult.id }, { $set: doc, $setOnInsert: { minecraft: { uuid: null, username: null }, team: null } }, { upsert: true })
|
||||
await coll.updateOne({ 'discord.id': userResult.id }, { $set: doc, $setOnInsert: { minecraft: { uuid: null, username: null }, teamInvites: [] } }, { upsert: true })
|
||||
|
||||
const token = createToken(tokenResponseData.access_token, tokenResponseData.refresh_token, tokenResponseData.expires_in, userResult.id )
|
||||
|
||||
|
20
web/server/api/minecraft/message/chattodiscord.js
Normal file
20
web/server/api/minecraft/message/chattodiscord.js
Normal file
@ -0,0 +1,20 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { content, uuid } = await readBody(event);
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
|
||||
const coll = db.collection('users')
|
||||
const doc = await coll.findOne({ 'minecraft.uuid': uuid })
|
||||
|
||||
await $fetch(config.discordHost + '/minecraft/sendchatmessage', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
username: doc.discord.username + ' | ' + doc.minecraft.username,
|
||||
// avatarURL: 'https://cdn.discordapp.com/avatars/' + doc.discord.id + '/' + doc.discord.avatarHash + '.png',
|
||||
avatarURL: 'https://api.mineatar.io/face/' + doc.minecraft.uuid + '?scale=16',
|
||||
content: content,
|
||||
}
|
||||
})
|
||||
|
||||
return { code: 'success' }
|
||||
});
|
10
web/server/api/minecraft/message/chattominecraft.js
Normal file
10
web/server/api/minecraft/message/chattominecraft.js
Normal file
@ -0,0 +1,10 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { discordId, content } = await readBody(event);
|
||||
|
||||
const coll = db.collection('users');
|
||||
const doc = await coll.findOne({ 'discord.id': discordId });
|
||||
|
||||
await sendRconCommand(`tellraw @a {"text":"(DC) ${doc.discord.username} > ${content}"}`)
|
||||
|
||||
return { whoo: 'hi' }
|
||||
});
|
18
web/server/api/minecraft/message/gametodiscord.js
Normal file
18
web/server/api/minecraft/message/gametodiscord.js
Normal file
@ -0,0 +1,18 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { content, uuid } = await readBody(event);
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
|
||||
const coll = db.collection('users')
|
||||
const doc = await coll.findOne({ 'minecraft.uuid': uuid })
|
||||
|
||||
await $fetch(config.discordHost + '/minecraft/sendgamemessage', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
avatarURL: 'https://api.mineatar.io/face/' + doc.minecraft.uuid + '?scale=16',
|
||||
content: content,
|
||||
}
|
||||
})
|
||||
|
||||
return { code: 'success' }
|
||||
});
|
18
web/server/api/team/acceptinvite.js
Normal file
18
web/server/api/team/acceptinvite.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { ObjectId } from 'mongodb'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { teamId } = await readBody(event);
|
||||
|
||||
const user = await getAuth(event)
|
||||
|
||||
const teamsColl = db.collection('teams')
|
||||
const usersColl = db.collection('users')
|
||||
|
||||
const team = await teamsColl.findOneAndUpdate({ _id: new ObjectId(teamId) }, { $inc: { count: 1 } })
|
||||
|
||||
if (!team.value) return createError({ statusCode: 500, statusMessage: 'Could not find team'})
|
||||
|
||||
await usersColl.updateOne({ _id: new ObjectId(user._id) }, { $set: { 'team.id': teamId, 'team.admin': false }})
|
||||
|
||||
return team
|
||||
});
|
8
web/server/api/team/all.js
Normal file
8
web/server/api/team/all.js
Normal file
@ -0,0 +1,8 @@
|
||||
export default defineEventHandler(async () => {
|
||||
const teamsColl = db.collection('teams')
|
||||
|
||||
const cursor = teamsColl.find();
|
||||
const teams = await cursor.toArray()
|
||||
|
||||
return teams
|
||||
});
|
16
web/server/api/team/cancelinvite.js
Normal file
16
web/server/api/team/cancelinvite.js
Normal file
@ -0,0 +1,16 @@
|
||||
import { ObjectId } from 'mongodb'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { id } = await readBody(event);
|
||||
|
||||
const user = await getAuth(event)
|
||||
|
||||
const teamsColl = db.collection('teams')
|
||||
const usersColl = db.collection('users')
|
||||
|
||||
const team = await teamsColl.findOne({ _id: new ObjectId(user.team.id) })
|
||||
|
||||
usersColl.updateOne({ _id: new ObjectId(id) }, { $pull: { teamInvites: team._id.toString() } })
|
||||
|
||||
return team
|
||||
});
|
21
web/server/api/team/create.post.js
Normal file
21
web/server/api/team/create.post.js
Normal file
@ -0,0 +1,21 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { teamName, teamColor } = await readBody(event);
|
||||
|
||||
if (!teamName || !teamColor) return createError({ statusCode: 400, statusMessage: 'teamName and teamColor are required' })
|
||||
if (!isHexColor(teamColor)) return createError({ statusCode: 400, statusMessage: 'Team color is not a valid hex code' })
|
||||
|
||||
const user = await getAuth(event)
|
||||
|
||||
if (user.team) return createError({ statusCode: 400, statusMessage: 'User already is in a team' })
|
||||
|
||||
const teamsColl = db.collection('teams')
|
||||
const usersColl = db.collection('users')
|
||||
|
||||
if (await teamsColl.findOne({ name: teamName })) return createError({ statusCode: 400, statusMessage: 'Team name already exists' })
|
||||
|
||||
const response = await teamsColl.insertOne({ name: teamName, color: teamColor, count: 1 })
|
||||
|
||||
await usersColl.findOneAndUpdate({ 'discord.id': user.discord.id }, { $set: { 'team.id': response.insertedId.toString(), 'team.admin': true } })
|
||||
|
||||
return response;
|
||||
});
|
14
web/server/api/team/demote.js
Normal file
14
web/server/api/team/demote.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { ObjectId } from 'mongodb'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { userId } = await readBody(event)
|
||||
|
||||
const user = await getAuth(event)
|
||||
|
||||
if (!user.team.admin) return createError({ statusCode: 403, statusMessage: 'Forbidden' })
|
||||
|
||||
const usersColl = db.collection('users')
|
||||
await usersColl.findOneAndUpdate({ _id: new ObjectId(userId) }, { $set: { 'team.admin': false } });
|
||||
|
||||
return { status: 'Success' }
|
||||
});
|
19
web/server/api/team/edit.js
Normal file
19
web/server/api/team/edit.js
Normal file
@ -0,0 +1,19 @@
|
||||
import { ObjectId } from 'mongodb'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { name, color } = await readBody(event);
|
||||
|
||||
if (!isHexColor(color)) return createError({ statusCode: 400, statusMessage: 'Team color is not a valid hex code' })
|
||||
|
||||
const user = await getAuth(event)
|
||||
|
||||
const teamsColl = db.collection('teams')
|
||||
|
||||
const team = await teamsColl.findOne({ _id: new ObjectId(user.team.id) });
|
||||
|
||||
if (team.name !== name && await teamsColl.findOne({ name: name })) return createError({ statusCode: 400, statusMessage: 'Team name already exists' })
|
||||
|
||||
await teamsColl.updateOne({ _id: new ObjectId(user.team.id) }, { $set: { name: name, color: color } })
|
||||
|
||||
return team
|
||||
});
|
10
web/server/api/team/index.js
Normal file
10
web/server/api/team/index.js
Normal file
@ -0,0 +1,10 @@
|
||||
import { ObjectId } from 'mongodb'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const user = await getAuth(event)
|
||||
|
||||
const teamsColl = db.collection('teams')
|
||||
const team = await teamsColl.findOne({ _id: new ObjectId(user.team.id) })
|
||||
|
||||
return team
|
||||
});
|
20
web/server/api/team/invite.js
Normal file
20
web/server/api/team/invite.js
Normal file
@ -0,0 +1,20 @@
|
||||
import { ObjectId } from 'mongodb'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { id } = await readBody(event);
|
||||
|
||||
const user = await getAuth(event)
|
||||
|
||||
const teamsColl = db.collection('teams')
|
||||
const usersColl = db.collection('users')
|
||||
|
||||
const team = await teamsColl.findOne({ _id: new ObjectId(user.team.id) })
|
||||
|
||||
const invitedUser = await usersColl.findOne({ _id: new ObjectId(id)});
|
||||
|
||||
if (invitedUser.team) return createError({ statusCode: 400, statusMessage: 'User already is in a team' })
|
||||
|
||||
usersColl.updateOne({ _id: new ObjectId(id) }, { $push: { teamInvites: team._id.toString() } })
|
||||
|
||||
return team
|
||||
});
|
16
web/server/api/team/leave.js
Normal file
16
web/server/api/team/leave.js
Normal file
@ -0,0 +1,16 @@
|
||||
import { ObjectId } from 'mongodb'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const user = await getAuth(event)
|
||||
|
||||
const teamsColl = db.collection('teams')
|
||||
const team = await teamsColl.findOneAndUpdate({ _id: new ObjectId(user.team.id) }, { $inc: { count: -1 }})
|
||||
|
||||
const usersColl = db.collection('users')
|
||||
await usersColl.findOneAndUpdate({ _id: new ObjectId(user._id) }, { $unset: { team: "" } })
|
||||
|
||||
if (team.value.count <= 1) {
|
||||
await teamsColl.deleteOne({ _id: new ObjectId(user.team.id )})
|
||||
}
|
||||
return team
|
||||
});
|
17
web/server/api/team/members.js
Normal file
17
web/server/api/team/members.js
Normal file
@ -0,0 +1,17 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
const user = await getAuth(event)
|
||||
|
||||
const usersColl = db.collection('users')
|
||||
const cursor = usersColl.find({ 'team.id': user.team.id })
|
||||
|
||||
if((await usersColl.countDocuments({ 'team.id': user.team.id })) === 0) {
|
||||
return createError({ statusCode: 500, statusMessage: 'No users were found' })
|
||||
}
|
||||
|
||||
const users = [];
|
||||
for await (const doc of cursor) {
|
||||
users.push(doc)
|
||||
}
|
||||
|
||||
return users;
|
||||
});
|
14
web/server/api/team/promote.js
Normal file
14
web/server/api/team/promote.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { ObjectId } from 'mongodb'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { userId } = await readBody(event)
|
||||
|
||||
const user = await getAuth(event)
|
||||
|
||||
if (!user.team.admin) return createError({ statusCode: 403, statusMessage: 'Forbidden' })
|
||||
|
||||
const usersColl = db.collection('users')
|
||||
await usersColl.findOneAndUpdate({ _id: new ObjectId(userId) },{ $set: { 'team.admin': true } });
|
||||
|
||||
return { status: 'Success' }
|
||||
});
|
7
web/server/api/team/unaffiliated.js
Normal file
7
web/server/api/team/unaffiliated.js
Normal file
@ -0,0 +1,7 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
const usersColl = db.collection('users')
|
||||
const cursor = usersColl.find({ team: { $exists: false } })
|
||||
const unaffiliatedUsers = await cursor.toArray()
|
||||
|
||||
return unaffiliatedUsers
|
||||
});
|
4
web/server/utils/check.js
Normal file
4
web/server/utils/check.js
Normal file
@ -0,0 +1,4 @@
|
||||
export const isHexColor = (str) => {
|
||||
const pattern = /^#([0-9A-F]{3}){1,2}$/i;
|
||||
return pattern.test(str);
|
||||
}
|
41
web/server/utils/rcon.js
Normal file
41
web/server/utils/rcon.js
Normal file
@ -0,0 +1,41 @@
|
||||
import { RCON } from 'minecraft-server-util';
|
||||
|
||||
const client = new RCON()
|
||||
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
let connected = false;
|
||||
|
||||
export const sendRconCommand = async (command) => {
|
||||
await connectRcon()
|
||||
|
||||
const message = await client.execute(command);
|
||||
|
||||
closeClient()
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
const connectRcon = async () => {
|
||||
if (connected) return;
|
||||
|
||||
await client.connect(config.rconHost);
|
||||
await client.login(config.rconPassword);
|
||||
|
||||
connected = true;
|
||||
}
|
||||
|
||||
const debounce = (callback, wait) => {
|
||||
let timeout = null;
|
||||
return (...args) => {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => {
|
||||
callback.apply(null, args);
|
||||
}, wait);
|
||||
};
|
||||
}
|
||||
|
||||
const closeClient = debounce(() => {
|
||||
client.close();
|
||||
connected = false;
|
||||
}, 5000)
|
Loading…
x
Reference in New Issue
Block a user