Compare commits

..

No commits in common. "d2ab24ed64292e53f56475e42386fae7fe5fe0c9" and "5aa8dce299ede51350cbc717c6dd68071622563e" have entirely different histories.

50 changed files with 687 additions and 1918 deletions

View File

@ -1,17 +0,0 @@
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,
}),
});
}
},
};

View File

@ -1,6 +1,6 @@
const { EmbedBuilder } = require('discord.js'); const { EmbedBuilder } = require('discord.js');
const registerEvents = ({ client }) => { const registerEvents = ({ createEmbed, client }) => {
client.player.on('trackStart', (queue, track) => { client.player.on('trackStart', (queue, track) => {

View File

@ -4,7 +4,6 @@ const { Player } = require('discord-player');
const fs = require('node:fs'); const fs = require('node:fs');
const path = require('node:path'); const path = require('node:path');
const dotenv = require('dotenv'); const dotenv = require('dotenv');
const express = require('express');
const createEmbed = require('./functions/createEmbed.js'); const createEmbed = require('./functions/createEmbed.js');
dotenv.config(); dotenv.config();
@ -16,25 +15,11 @@ const log = {
}; };
// Register client and music events // Register client and music events
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] }); const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMembers] });
client.player = new Player(client); client.player = new Player(client);
require('./functions/player.js').registerEvents({ client, createEmbed }); 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 // Command handling
client.commands = new Collection(); client.commands = new Collection();
@ -68,5 +53,3 @@ for (const file of eventFiles) {
} }
client.login(process.env.DISCORD_TOKEN); client.login(process.env.DISCORD_TOKEN);
module.exports.client = client;

File diff suppressed because it is too large Load Diff

View File

@ -17,8 +17,6 @@
"discord.js": "^14.7.1", "discord.js": "^14.7.1",
"distube": "^4.0.4", "distube": "^4.0.4",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"eslint": "^8.29.0", "eslint": "^8.29.0"
"express": "^4.18.2",
"ytdl-core": "^4.11.4"
} }
} }

View File

@ -1,38 +0,0 @@
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;

View File

@ -24,6 +24,7 @@ loom {
mods { mods {
"polarcraft-mod" { "polarcraft-mod" {
sourceSet sourceSets.main sourceSet sourceSets.main
sourceSet sourceSets.client
} }
} }

View File

@ -0,0 +1,10 @@
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.
}
}

View File

@ -0,0 +1,15 @@
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
}
}

View File

@ -0,0 +1,11 @@
{
"required": true,
"package": "com.xeovalyte.polarcraft.mixin.client",
"compatibilityLevel": "JAVA_17",
"client": [
"ExampleClientMixin"
],
"injectors": {
"defaultRequire": 1
}
}

View File

@ -1,23 +1,33 @@
package com.xeovalyte.polarcraft; package com.xeovalyte.polarcraft;
import com.xeovalyte.polarcraft.util.messageFunctions;
import com.xeovalyte.polarcraft.util.verifyFunction;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.fabricmc.loader.api.FabricLoader; 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.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import java.io.BufferedReader;
import java.io.IOException; 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.nio.charset.StandardCharsets;
import java.io.File; import java.io.File;
import com.google.gson.JsonObject;
import com.google.gson.JsonElement;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import java.util.UUID;
import net.fabricmc.fabric.api.message.v1.ServerMessageEvents; import net.fabricmc.fabric.api.message.v1.ServerMessageEvents;
public class PolarcraftMod implements ModInitializer { public class PolarcraftMod implements ModInitializer {
@ -29,9 +39,8 @@ public class PolarcraftMod implements ModInitializer {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static final File CONFIG_FILE = new File(FabricLoader.getInstance().getConfigDir().toFile(), "polarcraft.json"); private static final File CONFIG_FILE = new File(FabricLoader.getInstance().getConfigDir().toFile(), "polarcraft.json");
public static String configChatMessageUrl = "https://example.com/api/minecraft/message/chattodiscord"; private String configWebhookUrl = "https://discordapp.com/api/webhooks/webhookid/webhooktoken";
public static String configGameMessageUrl = "https://example.com/api/minecraft/message/gametodiscord"; private String configVerifyUrl = "https://example.com/api/minecraft/verifyuuid";
public static String configVerifyUrl = "https://example.com/api/minecraft/verifyuuid";
@Override @Override
public void onInitialize() { public void onInitialize() {
@ -42,17 +51,15 @@ public class PolarcraftMod implements ModInitializer {
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
ServerPlayerEntity player = (ServerPlayerEntity) handler.player; 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) -> { ServerMessageEvents.CHAT_MESSAGE.register((message, sender, params) -> {
messageFunctions.sendChatMessage(message, sender); onChatMessage(message, sender);
});
ServerMessageEvents.GAME_MESSAGE.register((server, message, overlay) -> {
onGameMessage(server, message);
}); });
} }
@ -64,8 +71,7 @@ public class PolarcraftMod implements ModInitializer {
try { try {
MyModConfig config = GSON.fromJson(FileUtils.readFileToString(CONFIG_FILE, StandardCharsets.UTF_8), MyModConfig.class); MyModConfig config = GSON.fromJson(FileUtils.readFileToString(CONFIG_FILE, StandardCharsets.UTF_8), MyModConfig.class);
configChatMessageUrl = config.chatMessageUrl; configWebhookUrl = config.webhookUrl;
configGameMessageUrl = config.gameMessageUrl;
configVerifyUrl = config.verifyUrl; configVerifyUrl = config.verifyUrl;
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@ -74,21 +80,120 @@ public class PolarcraftMod implements ModInitializer {
private void saveConfig() { private void saveConfig() {
try { try {
FileUtils.writeStringToFile(CONFIG_FILE, GSON.toJson(new MyModConfig(configChatMessageUrl, configGameMessageUrl,configVerifyUrl)), StandardCharsets.UTF_8); FileUtils.writeStringToFile(CONFIG_FILE, GSON.toJson(new MyModConfig(configWebhookUrl, configVerifyUrl)), StandardCharsets.UTF_8);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
public static class MyModConfig { public static class MyModConfig {
public String chatMessageUrl; public String webhookUrl;
public String gameMessageUrl;
public String verifyUrl; public String verifyUrl;
public MyModConfig(String chatMessageUrl, String gameMessageUrl,String verifyUrl) { public MyModConfig(String webhookUrl, String verifyUrl) {
this.chatMessageUrl = chatMessageUrl; this.webhookUrl = webhookUrl;
this.gameMessageUrl = gameMessageUrl;
this.verifyUrl = verifyUrl; 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();
}
}
} }

View File

@ -0,0 +1,15 @@
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
}
}

View File

@ -1,31 +0,0 @@
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() + "]");
}
}

View File

@ -1,27 +0,0 @@
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());
}
}

View File

@ -1,74 +0,0 @@
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();
}
}
}

View File

@ -1,66 +0,0 @@
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();
}
}
}

View File

@ -13,14 +13,18 @@
}, },
"license": "CC0-1.0", "license": "CC0-1.0",
"icon": "assets/polarcraft-mod/icon.png", "icon": "assets/polarcraft-mod/icon.png",
"environment": "server", "environment": "*",
"entrypoints": { "entrypoints": {
"main": [ "main": [
"com.xeovalyte.polarcraft.PolarcraftMod" "com.xeovalyte.polarcraft.PolarcraftMod"
] ]
}, },
"mixins": [ "mixins": [
"polarcraft-mod.mixins.json" "polarcraft-mod.mixins.json",
{
"config": "polarcraft-mod.client.mixins.json",
"environment": "client"
}
], ],
"depends": { "depends": {
"fabricloader": ">=0.14.19", "fabricloader": ">=0.14.19",

View File

@ -3,8 +3,7 @@
"package": "com.xeovalyte.polarcraft.mixin", "package": "com.xeovalyte.polarcraft.mixin",
"compatibilityLevel": "JAVA_17", "compatibilityLevel": "JAVA_17",
"mixins": [ "mixins": [
"MixinPlayerAdvancementTracker", "ExampleMixin"
"MixinPlayerEntity"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1

View File

@ -1,6 +1,6 @@
{ {
"root": true, "root": true,
"extends": ["@nuxt/eslint-config", "plugin:tailwindcss/recommended"], "extends": ["@nuxt/eslint-config"],
"rules": { "rules": {
"vue/max-attributes-per-line": ["error", { "vue/max-attributes-per-line": ["error", {
"singleline": { "singleline": {

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="h-screen w-full overflow-y-auto"> <div class="w-full h-screen overflow-y-auto">
<NuxtLayout :name="layout" /> <NuxtLayout :name="layout" />
</div> </div>
</template> </template>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="flex w-full flex-col items-center text-primary"> <div class="w-full text-primary flex items-center flex-col">
<div v-if="!user.minecraft.uuid" class="flex flex-col items-center"> <div v-if="!user.minecraft.uuid" class="flex flex-col items-center">
<p class="mb-10 max-w-xl text-sm sm:text-base"> <p class="max-w-xl mb-10 sm:text-base text-sm">
Je bent momenteel niet gewhitelist. Om toegang te krijgen tot de Minecraft server moet je in Minecraft naar de 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 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. te zien, vul deze code hieronder in.

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="flex items-center border-b border-b-gray-700 bg-neutral-800 px-5"> <div class="bg-neutral-800 border-b border-b-gray-700 flex items-center px-5">
<h1 class="text-2xl font-bold text-primary">Polarcraft</h1> <h1 class="text-primary text-2xl font-bold">Polarcraft</h1>
<Button outline class="ml-auto" @click="logout">Logout</Button> <Button outline class="ml-auto" @click="logout">Logout</Button>
</div> </div>
</template> </template>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="flex flex-col bg-neutral-800 px-2 pb-14 pt-5 text-gray-300"> <div class="bg-neutral-800 text-gray-300 px-2 pt-5 pb-14 flex flex-col">
<NuxtLink to="/" class="sidebar-item"> <NuxtLink to="/" class="sidebar-item">
<Icon size="1.5em" name="ph:house" class="mr-3" /> <Icon size="1.5em" name="ph:house" class="mr-3" />
Home Home

View File

@ -1,180 +0,0 @@
<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>

View File

@ -1,86 +1,20 @@
<template> <template>
<p class="my-10 text-center text-gray-300"> <p class="text-gray-300 text-center my-10">
Je zit momenteel niet in een team. Maak een team aan of wacht tot dat je geinvite wordt Je zit momenteel niet in een team. Maak een team aan of wacht tot dat je geinvite wordt
</p> </p>
<div class="mb-5 flex w-full justify-center gap-10"> <div class="flex w-full justify-center gap-10 mb-5">
<span <span class="text-primary font-bold hover:cursor-pointer" :class="{'underline underline-offset-4': !createTeam}" @click="createTeam = false">Team Invites</span>
class="font-bold text-primary hover:cursor-pointer" :class="{ 'underline underline-offset-4': !createTeam.show }" <span class="text-primary font-bold hover:cursor-pointer" :class="{'underline underline-offset-4': createTeam}" @click="createTeam = true">Create Team</span>
@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>
<div v-if="!createTeam.show" class="text-center text-gray-300"> <div v-if="!createTeam" class="text-center text-gray-300">
<h2 v-if="!user.teamInvites.length">You don't have any team invites</h2> You don't have any team invites
<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>
<div v-else class="flex w-full flex-col items-center gap-5"> <div v-else class="w-full flex flex-col items-center gap-5">
<Input v-model:value="createTeam.name" class="w-full max-w-sm">Naam / Prefix</Input> <Input class="w-full max-w-sm">Naam / Prefix</Input>
<Colorpicker v-model:value="createTeam.color" class="w-full max-w-sm" /> <Colorpicker class="w-full max-w-sm" />
<Button @click="handleCreateTeam">Create Team</Button>
</div> </div>
</template> </template>
<script setup> <script setup>
const user = useState('user') const createTeam = ref(false)
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> </script>

View File

@ -1,14 +1,14 @@
<template> <template>
<div class="h-full bg-neutral-900"> <div class="h-full bg-neutral-900">
<div v-if="user" class="hidden h-full grid-cols-desktoplayout grid-rows-desktoplayout sm:grid"> <div class="hidden sm:grid grid-cols-desktoplayout grid-rows-desktoplayout h-full">
<LayoutNavbar class="col-span-2" /> <LayoutNavbar class="col-span-2" />
<LayoutSidebar v-if="user.minecraft.uuid" class="" /> <LayoutSidebar v-if="user.minecraft.uuid" class="" />
<div class="overflow-y-auto px-10 pt-5" :class="{ 'col-span-2': !user.minecraft.uuid }"> <div class="overflow-y-auto px-10 pt-5" :class="{ 'col-span-2': !user.minecraft.uuid }">
<NuxtPage /> <NuxtPage />
</div> </div>
</div> </div>
<div v-if="user" class="h-full sm:hidden"> <div class="sm:hidden h-full">
<div class="overflow-y-auto p-2"> <div class="overflow-y-auto px-2 py-2">
<NuxtPage /> <NuxtPage />
</div> </div>
</div> </div>

View File

@ -13,14 +13,11 @@ export default defineNuxtConfig({
runtimeConfig: { runtimeConfig: {
discordId: '', discordId: '',
discordSecret: '', discordSecret: '',
discordHost: '',
jwtSecret: '', jwtSecret: '',
dbUrl: '', dbUrl: '',
mineckerHost: '', mineckerHost: '',
mineckerApiKey: '', mineckerApiKey: '',
rconPassword: '', mincecraftContainer: 'mc-school',
rconPort: '25575',
rconHost: 'localhost',
public: { 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', 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
View File

@ -11,7 +11,6 @@
"@xeovalyte/nuxt-xvtoast": "^1.1.3", "@xeovalyte/nuxt-xvtoast": "^1.1.3",
"@xeovalyte/nuxt-xvui": "git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git", "@xeovalyte/nuxt-xvui": "git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git",
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.0",
"minecraft-server-util": "^5.4.2",
"mongodb": "^5.3.0", "mongodb": "^5.3.0",
"socket.io-client": "^4.6.1", "socket.io-client": "^4.6.1",
"surrealdb.js": "^0.6.0" "surrealdb.js": "^0.6.0"
@ -25,7 +24,6 @@
"@vueuse/core": "^10.1.0", "@vueuse/core": "^10.1.0",
"@vueuse/nuxt": "^10.1.0", "@vueuse/nuxt": "^10.1.0",
"eslint": "^8.39.0", "eslint": "^8.39.0",
"eslint-plugin-tailwindcss": "^3.11.0",
"nuxt": "^3.4.2", "nuxt": "^3.4.2",
"nuxt-icon": "^0.3.3" "nuxt-icon": "^0.3.3"
} }
@ -3160,7 +3158,7 @@
} }
}, },
"node_modules/@xeovalyte/nuxt-xvui": { "node_modules/@xeovalyte/nuxt-xvui": {
"resolved": "git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git#53b253beae85b014c2556291aaa9f8f94fc765d5", "resolved": "git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git#e5bb7302f0626b39aa7b3a73bd4109b03702a9c7",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@nuxt/eslint-config": "^0.1.1", "@nuxt/eslint-config": "^0.1.1",
@ -5359,22 +5357,6 @@
"url": "https://opencollective.com/eslint" "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": { "node_modules/eslint-plugin-vue": {
"version": "9.11.0", "version": "9.11.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.11.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.11.0.tgz",
@ -8110,22 +8092,6 @@
"url": "https://github.com/sponsors/sindresorhus" "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": { "node_modules/minimatch": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@ -15838,7 +15804,7 @@
} }
}, },
"@xeovalyte/nuxt-xvui": { "@xeovalyte/nuxt-xvui": {
"version": "git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git#53b253beae85b014c2556291aaa9f8f94fc765d5", "version": "git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git#e5bb7302f0626b39aa7b3a73bd4109b03702a9c7",
"from": "@xeovalyte/nuxt-xvui@git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git", "from": "@xeovalyte/nuxt-xvui@git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git",
"requires": { "requires": {
"@nuxt/eslint-config": "^0.1.1", "@nuxt/eslint-config": "^0.1.1",
@ -17461,16 +17427,6 @@
} }
} }
}, },
"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": { "eslint-plugin-vue": {
"version": "9.11.0", "version": "9.11.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.11.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.11.0.tgz",
@ -19504,19 +19460,6 @@
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
"dev": true "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": { "minimatch": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",

View File

@ -7,8 +7,7 @@
"generate": "nuxt generate", "generate": "nuxt generate",
"preview": "nuxt preview", "preview": "nuxt preview",
"postinstall": "nuxt prepare", "postinstall": "nuxt prepare",
"lint": "eslint .", "lint": "eslint ."
"lint-fix": "eslint . --fix"
}, },
"devDependencies": { "devDependencies": {
"@nuxt/devtools": "^0.4.2", "@nuxt/devtools": "^0.4.2",
@ -19,7 +18,6 @@
"@vueuse/core": "^10.1.0", "@vueuse/core": "^10.1.0",
"@vueuse/nuxt": "^10.1.0", "@vueuse/nuxt": "^10.1.0",
"eslint": "^8.39.0", "eslint": "^8.39.0",
"eslint-plugin-tailwindcss": "^3.11.0",
"nuxt": "^3.4.2", "nuxt": "^3.4.2",
"nuxt-icon": "^0.3.3" "nuxt-icon": "^0.3.3"
}, },
@ -28,7 +26,6 @@
"@xeovalyte/nuxt-xvtoast": "^1.1.3", "@xeovalyte/nuxt-xvtoast": "^1.1.3",
"@xeovalyte/nuxt-xvui": "git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git", "@xeovalyte/nuxt-xvui": "git+https://gitea.xeovalyte.dev/xeovalyte/nuxt-xvui.git",
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.0",
"minecraft-server-util": "^5.4.2",
"mongodb": "^5.3.0", "mongodb": "^5.3.0",
"socket.io-client": "^4.6.1", "socket.io-client": "^4.6.1",
"surrealdb.js": "^0.6.0" "surrealdb.js": "^0.6.0"

View File

@ -1,16 +1,16 @@
<template> <template>
<div class="flex h-full w-full flex-col text-primary"> <div class="w-full h-full text-primary flex flex-col">
<h1 class="mb-10 mt-20 text-center text-5xl font-bold">Welkom, {{ user.discord.username }}</h1> <h1 class="text-5xl font-bold text-center mt-20 mb-10">Welkom, {{ user.discord.username }}</h1>
<Whitelist v-if="!user.minecraft.uuid" /> <Whitelist v-if="!user.minecraft.uuid" />
<div v-else class="flex w-full max-w-3xl flex-wrap justify-center gap-4"> <div v-else class="flex justify-center gap-4 flex-wrap max-w-3xl w-full">
<img :src="'https://api.mineatar.io/face/' + user.minecraft.uuid + '?scale=16'" class="w-24 rounded shadow"> <img :src="'https://api.mineatar.io/face/' + user.minecraft.uuid + '?scale=16'" class="w-24 rounded shadow">
<div class="flex w-full max-w-md rounded border-2 border-primary p-4"> <div class="rounded flex border-2 border-primary p-4 w-full max-w-md">
<ul class="my-auto"> <ul class="my-auto">
<li>Username: <b>{{ user.minecraft.username }}</b></li> <li>Username: <b>{{ user.minecraft.username }}</b></li>
<li>UUID: <b>{{ user.minecraft.uuid }}</b></li> <li>UUID: <b>{{ user.minecraft.uuid }}</b></li>
</ul> </ul>
</div> </div>
<div class="mt-2 flex w-full justify-center gap-4"> <div class="w-full flex justify-center gap-4 mt-2">
<Button type="danger" @click="removeWhitelist"> <Button type="danger" @click="removeWhitelist">
Remove from whitelist Remove from whitelist
</Button> </Button>

View File

@ -1,16 +1,16 @@
<template> <template>
<div class="flex h-screen w-full flex-col items-center justify-center bg-transparent px-2 text-primary"> <div class="w-full h-screen text-primary bg-opacity-0 flex justify-center items-center flex-col px-2">
<h1 class="mb-5 text-center text-3xl font-bold sm:text-5xl">Polarcraft S5</h1> <h1 class="sm:text-5xl text-3xl font-bold text-center mb-5">Polarcraft S5</h1>
<p class="mb-10 max-w-xl text-sm sm:text-base"> <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="highlight">/ticket</span> commando uit te voeren. <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.
</p> </p>
<Button @click="navigateTo(config.public.redirectUrl, { external: true })"> <Button @click="navigateTo(config.public.redirectUrl, { external: true })">
Log in with Discord Log in with Discord
<Icon size="1.6em" name="ic:baseline-discord" /> <Icon size="1.6em" name="ic:baseline-discord" />
</Button> </Button>
<div class="absolute left-0 top-0 -z-10 h-screen w-full overflow-hidden"> <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 scale-105 object-cover blur-[1px] brightness-75"> <img src="../assets/pictures/diamond_wall.png" class="h-full w-full object-cover brightness-75 blur-[1px] scale-105">
</div> </div>
</div> </div>
</template> </template>

View File

@ -1,17 +1,8 @@
<template> <template>
<div> <div>
<h1 class="text-2xl font-bold text-primary"> <h1 class="font-bold text-2xl text-primary">
Team Team
</h1> </h1>
<TeamNone v-if="!user.team" /> <TeamNone />
<TeamDefault v-else />
</div> </div>
</template> </template>
<script setup>
const user = useState('user')
definePageMeta({
middleware: ["auth"]
})
</script>

View File

@ -37,7 +37,7 @@ export default defineEventHandler(async (event) => {
}, },
} }
await coll.updateOne({ 'discord.id': userResult.id }, { $set: doc, $setOnInsert: { minecraft: { uuid: null, username: null }, teamInvites: [] } }, { upsert: true }) await coll.updateOne({ 'discord.id': userResult.id }, { $set: doc, $setOnInsert: { minecraft: { uuid: null, username: null }, team: null } }, { upsert: true })
const token = createToken(tokenResponseData.access_token, tokenResponseData.refresh_token, tokenResponseData.expires_in, userResult.id ) const token = createToken(tokenResponseData.access_token, tokenResponseData.refresh_token, tokenResponseData.expires_in, userResult.id )

View File

@ -1,20 +0,0 @@
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' }
});

View File

@ -1,10 +0,0 @@
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' }
});

View File

@ -1,18 +0,0 @@
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' }
});

View File

@ -1,18 +0,0 @@
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
});

View File

@ -1,8 +0,0 @@
export default defineEventHandler(async () => {
const teamsColl = db.collection('teams')
const cursor = teamsColl.find();
const teams = await cursor.toArray()
return teams
});

View File

@ -1,16 +0,0 @@
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
});

View File

@ -1,21 +0,0 @@
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;
});

View File

@ -1,14 +0,0 @@
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' }
});

View File

@ -1,19 +0,0 @@
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
});

View File

@ -1,10 +0,0 @@
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
});

View File

@ -1,20 +0,0 @@
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
});

View File

@ -1,16 +0,0 @@
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
});

View File

@ -1,17 +0,0 @@
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;
});

View File

@ -1,14 +0,0 @@
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' }
});

View File

@ -1,7 +0,0 @@
export default defineEventHandler(async (event) => {
const usersColl = db.collection('users')
const cursor = usersColl.find({ team: { $exists: false } })
const unaffiliatedUsers = await cursor.toArray()
return unaffiliatedUsers
});

View File

@ -1,4 +0,0 @@
export const isHexColor = (str) => {
const pattern = /^#([0-9A-F]{3}){1,2}$/i;
return pattern.test(str);
}

View File

@ -1,41 +0,0 @@
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)