Lots of improvements and changes
This commit is contained in:
parent
98d73ea593
commit
8121b9b975
@ -36,7 +36,7 @@ module.exports = {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await ticketChannel.send({ embeds: [createEmbed.basic(`${interaction.user} created a ticket`)]});
|
await ticketChannel.send({ embeds: [createEmbed.basic(`${interaction.user} created a ticket`)] });
|
||||||
|
|
||||||
interaction.editReply({ embeds: [createEmbed.basic(`${ticketChannel} has been created`)], emphemeral: true });
|
interaction.editReply({ embeds: [createEmbed.basic(`${ticketChannel} has been created`)], emphemeral: true });
|
||||||
|
|
||||||
@ -52,14 +52,14 @@ module.exports = {
|
|||||||
.setStyle(ButtonStyle.Danger),
|
.setStyle(ButtonStyle.Danger),
|
||||||
);
|
);
|
||||||
|
|
||||||
const closeMessage = await interaction.reply({ embeds: [createEmbed.basic(`Closing ticket in 10 seconds...`)], components: [cancelRow]});
|
const closeMessage = await interaction.reply({ embeds: [createEmbed.basic('Closing ticket in 10 seconds...')], components: [cancelRow] });
|
||||||
const collector = closeMessage.createMessageComponentCollector();
|
const collector = closeMessage.createMessageComponentCollector();
|
||||||
|
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
try {
|
try {
|
||||||
interaction.channel.delete()
|
interaction.channel.delete();
|
||||||
} catch {}
|
} catch {}
|
||||||
}, 10000)
|
}, 10000);
|
||||||
|
|
||||||
collector.on('collect', async () => {
|
collector.on('collect', async () => {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"lint": "eslint .",
|
||||||
|
"lint-fix": "eslint . --fix"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
@ -7,14 +7,14 @@ const router = express.Router();
|
|||||||
router.post('/createchannels', async (req, res) => {
|
router.post('/createchannels', async (req, res) => {
|
||||||
const { name, discordId } = req.body;
|
const { name, discordId } = req.body;
|
||||||
|
|
||||||
if (!name || !discordId ) return res.status(400).send({ error: 'Name en discordId zijn vereist' });
|
if (!name || !discordId) return res.status(400).send({ error: 'Name en discordId zijn vereist' });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
|
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
|
||||||
|
|
||||||
const category = await guild.channels.fetch(process.env.TEAM_CATEGORY_ID);
|
const category = await guild.channels.fetch(process.env.TEAM_CATEGORY_ID);
|
||||||
|
|
||||||
const member = await guild.members.fetch(discordId)
|
const member = await guild.members.fetch(discordId);
|
||||||
|
|
||||||
const textChannel = await guild.channels.create({
|
const textChannel = await guild.channels.create({
|
||||||
name: name,
|
name: name,
|
||||||
@ -27,9 +27,9 @@ router.post('/createchannels', async (req, res) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: member.id,
|
id: member.id,
|
||||||
allow: [PermissionsBitField.Flags.ViewChannel]
|
allow: [PermissionsBitField.Flags.ViewChannel],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const voiceChannel = await guild.channels.create({
|
const voiceChannel = await guild.channels.create({
|
||||||
@ -43,15 +43,15 @@ router.post('/createchannels', async (req, res) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: member.id,
|
id: member.id,
|
||||||
allow: [PermissionsBitField.Flags.ViewChannel]
|
allow: [PermissionsBitField.Flags.ViewChannel],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
res.send({ textChannel, voiceChannel });
|
res.send({ textChannel, voiceChannel });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
return res.status(500).send({ error: 'Error tijdens het maken van discord channels' })
|
return res.status(500).send({ error: 'Error tijdens het maken van discord channels' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -59,86 +59,86 @@ router.post('/createchannels', async (req, res) => {
|
|||||||
router.post('/deletechannels', async (req, res) => {
|
router.post('/deletechannels', async (req, res) => {
|
||||||
const { textChannelId, voiceChannelId } = req.body;
|
const { textChannelId, voiceChannelId } = req.body;
|
||||||
|
|
||||||
if (!textChannelId, !voiceChannelId ) return res.status(400).send({ error: 'textChannelId en voiceChannelId zijn vereist' });
|
if (!textChannelId, !voiceChannelId) return res.status(400).send({ error: 'textChannelId en voiceChannelId zijn vereist' });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
|
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
|
||||||
|
|
||||||
const textChannel = await guild.channels.fetch(textChannelId);
|
const textChannel = await guild.channels.fetch(textChannelId);
|
||||||
const voiceChannel = await guild.channels.fetch(voiceChannelId);
|
const voiceChannel = await guild.channels.fetch(voiceChannelId);
|
||||||
|
|
||||||
await textChannel.delete()
|
await textChannel.delete();
|
||||||
await voiceChannel.delete()
|
await voiceChannel.delete();
|
||||||
|
|
||||||
res.send({ status: 'success' });
|
res.send({ status: 'success' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
return res.status(500).send({ error: 'Error tijdens het verwijderen van discord channels' })
|
return res.status(500).send({ error: 'Error tijdens het verwijderen van discord channels' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/removeteammember', async (req, res) => {
|
router.post('/removeteammember', async (req, res) => {
|
||||||
const { textChannelId, voiceChannelId, discordId } = req.body;
|
const { textChannelId, voiceChannelId, discordId } = req.body;
|
||||||
|
|
||||||
if (!textChannelId, !voiceChannelId, !discordId ) return res.status(400).send({ error: 'textChannelId, voiceChannelId en discordId zijn vereist' });
|
if (!textChannelId, !voiceChannelId, !discordId) return res.status(400).send({ error: 'textChannelId, voiceChannelId en discordId zijn vereist' });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
|
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
|
||||||
const member = await guild.members.fetch(discordId)
|
const member = await guild.members.fetch(discordId);
|
||||||
|
|
||||||
const textChannel = await guild.channels.fetch(textChannelId);
|
const textChannel = await guild.channels.fetch(textChannelId);
|
||||||
const voiceChannel = await guild.channels.fetch(voiceChannelId);
|
const voiceChannel = await guild.channels.fetch(voiceChannelId);
|
||||||
|
|
||||||
await textChannel.permissionOverwrites.delete(member)
|
await textChannel.permissionOverwrites.delete(member);
|
||||||
await voiceChannel.permissionOverwrites.delete(member)
|
await voiceChannel.permissionOverwrites.delete(member);
|
||||||
|
|
||||||
res.send({ status: 'success' });
|
res.send({ status: 'success' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
return res.status(500).send({ error: 'Error tijdens het verwijderen van een team member' })
|
return res.status(500).send({ error: 'Error tijdens het verwijderen van een team member' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/addteammember', async (req, res) => {
|
router.post('/addteammember', async (req, res) => {
|
||||||
const { textChannelId, voiceChannelId, discordId } = req.body;
|
const { textChannelId, voiceChannelId, discordId } = req.body;
|
||||||
|
|
||||||
if (!textChannelId, !voiceChannelId, !discordId ) return res.status(400).send({ error: 'textChannelId, voiceChannelId en discordId zijn vereist' });
|
if (!textChannelId, !voiceChannelId, !discordId) return res.status(400).send({ error: 'textChannelId, voiceChannelId en discordId zijn vereist' });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
|
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
|
||||||
const member = await guild.members.fetch(discordId)
|
const member = await guild.members.fetch(discordId);
|
||||||
|
|
||||||
const textChannel = await guild.channels.fetch(textChannelId);
|
const textChannel = await guild.channels.fetch(textChannelId);
|
||||||
const voiceChannel = await guild.channels.fetch(voiceChannelId);
|
const voiceChannel = await guild.channels.fetch(voiceChannelId);
|
||||||
|
|
||||||
await textChannel.permissionOverwrites.edit(member, { ViewChannel: true })
|
await textChannel.permissionOverwrites.edit(member, { ViewChannel: true });
|
||||||
await voiceChannel.permissionOverwrites.edit(member, { ViewChannel: true })
|
await voiceChannel.permissionOverwrites.edit(member, { ViewChannel: true });
|
||||||
|
|
||||||
res.send({ status: 'success' });
|
res.send({ status: 'success' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
return res.status(500).send({ error: 'Error tijdens het toevoegen van team member' })
|
return res.status(500).send({ error: 'Error tijdens het toevoegen van team member' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/edit', async (req, res) => {
|
router.post('/edit', async (req, res) => {
|
||||||
const { textChannelId, voiceChannelId, name } = req.body;
|
const { textChannelId, voiceChannelId, name } = req.body;
|
||||||
|
|
||||||
if (!textChannelId, !voiceChannelId, !name ) return res.status(400).send({ error: 'textChannelId, voiceChannelId en name zijn vereist' });
|
if (!textChannelId, !voiceChannelId, !name) return res.status(400).send({ error: 'textChannelId, voiceChannelId en name zijn vereist' });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
|
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
|
||||||
|
|
||||||
const textChannel = await guild.channels.fetch(textChannelId);
|
const textChannel = await guild.channels.fetch(textChannelId);
|
||||||
const voiceChannel = await guild.channels.fetch(voiceChannelId);
|
const voiceChannel = await guild.channels.fetch(voiceChannelId);
|
||||||
|
|
||||||
await textChannel.edit({ name: name })
|
await textChannel.edit({ name: name });
|
||||||
await voiceChannel.edit({ name: name })
|
await voiceChannel.edit({ name: name });
|
||||||
|
|
||||||
res.send({ status: 'success' });
|
res.send({ status: 'success' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
return res.status(500).send({ error: 'Error tijds het veranderen van Discord channel naam' })
|
return res.status(500).send({ error: 'Error tijds het veranderen van Discord channel naam' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,27 +1,47 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const index = require('../index')
|
const index = require('../index');
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.post('/changenickname', async (req, res) => {
|
router.post('/changenickname', async (req, res) => {
|
||||||
const { nickname, discordId } = req.body;
|
const { nickname, discordId } = req.body;
|
||||||
|
|
||||||
if (!nickname || !discordId ) return res.status(400).send({ error: 'Nickname en discordId zijn vereist' });
|
if (!nickname || !discordId) return res.status(400).send({ error: 'Nickname en discordId zijn vereist' });
|
||||||
|
|
||||||
|
const nick = nickname.length > 32 ? nickname.slice(0, 32) : nickname;
|
||||||
|
|
||||||
const nick = nickname.length > 32 ? nickname.slice(0, 32) : nickname
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
|
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
|
||||||
|
|
||||||
const member = await guild.members.fetch(discordId)
|
const member = await guild.members.fetch(discordId);
|
||||||
|
|
||||||
await member.edit({ nick: nick })
|
await member.edit({ nick: nick });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
return res.status(500).send({ error: 'Error tijds het veranderen van de nickname' })
|
return res.status(500).send({ error: 'Error tijds het veranderen van de nickname' });
|
||||||
}
|
}
|
||||||
|
|
||||||
res.send({ status: 'success' });
|
res.send({ status: 'success' });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post('/ban', async (req, res) => {
|
||||||
|
const { discordId, reason } = req.body;
|
||||||
|
|
||||||
|
if (!reason || !discordId) return res.status(400).send({ error: 'Reason en discordId zijn vereist' });
|
||||||
|
|
||||||
|
try {
|
||||||
|
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
|
||||||
|
|
||||||
|
const member = await guild.members.fetch(discordId);
|
||||||
|
|
||||||
|
await member.ban({ deleteMessageSeconds: 24 * 3600, reason: reason });
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
return res.status(500).send({ error: 'Error tijds het bannen van gebruiker' });
|
||||||
|
}
|
||||||
|
|
||||||
|
res.send({ status: 'success' });
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
te zien, vul deze code hieronder in.
|
te zien, vul deze code hieronder in.
|
||||||
</p>
|
</p>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<Input v-model:value="code">Code</Input>
|
<Input v-model="code">Code</Input>
|
||||||
<Button @click="submitCode">Submit</Button>
|
<Button @click="submitCode">Submit</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,12 +16,16 @@
|
|||||||
<Icon size="1.5em" name="ph:map-trifold" class="mr-3" />
|
<Icon size="1.5em" name="ph:map-trifold" class="mr-3" />
|
||||||
Map
|
Map
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
<div v-if="user && user.admin" class="mt-auto">
|
<div v-if="user && user.role.admin" class="mt-auto space-y-1">
|
||||||
<h2 class="ml-2 text-gray-400">Adminstration</h2>
|
<h2 class="ml-2 text-gray-400">Moderation</h2>
|
||||||
<NuxtLink to="/admin/users" class="sidebar-item">
|
<NuxtLink to="/mod/users" class="sidebar-item">
|
||||||
<Icon size="1.5em" name="ph:users-three" class="mr-3" />
|
<Icon size="1.5em" name="ph:users-three" class="mr-3" />
|
||||||
Users
|
Users
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
|
<NuxtLink to="/mod/server" class="sidebar-item">
|
||||||
|
<Icon size="1.5em" name="ph:cpu" class="mr-3" />
|
||||||
|
Server Control
|
||||||
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
<Modal v-if="editTeamModal.open" title="Edit team" @close="editTeamModal.open = false" @submit="editTeam">
|
<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>
|
<Input v-model="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" />
|
<Colorpicker v-model="editTeamModal.color" input-background-class="bg-neutral-800" class="w-full max-w-sm" />
|
||||||
</Modal>
|
</Modal>
|
||||||
<div class="mx-auto my-10 max-w-2xl">
|
<div class="mx-auto my-10 max-w-2xl">
|
||||||
<h2 class="mb-2 text-xl font-bold text-primary">Team Information</h2>
|
<h2 class="mb-2 text-xl font-bold text-primary">Team Information</h2>
|
||||||
|
@ -28,8 +28,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="flex w-full flex-col items-center gap-5">
|
<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</Input>
|
<Input v-model="createTeam.name" class="w-full max-w-sm">Naam</Input>
|
||||||
<Colorpicker v-model:value="createTeam.color" class="w-full max-w-sm" />
|
<Colorpicker v-model="createTeam.color" class="w-full max-w-sm" />
|
||||||
<Button @click="handleCreateTeam">Create Team</Button>
|
<Button @click="handleCreateTeam">Create Team</Button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -5,7 +5,7 @@ export default defineNuxtRouteMiddleware(async (to) => {
|
|||||||
const user = await $fetch('/api/auth/user')
|
const user = await $fetch('/api/auth/user')
|
||||||
useState('user', () => user)
|
useState('user', () => user)
|
||||||
|
|
||||||
if (to.meta.admin && !user.admin) return navigateTo('/')
|
if (to.meta.moderator && !user.role.moderator) return navigateTo('/')
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
|
4249
web/package-lock.json
generated
4249
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -11,18 +11,18 @@
|
|||||||
"lint-fix": "eslint . --fix"
|
"lint-fix": "eslint . --fix"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxt/devtools": "^0.4.2",
|
"@nuxt/devtools": "^0.5.0",
|
||||||
"@nuxt/image-edge": "^1.0.0-28059208.2abef1b",
|
"@nuxt/image-edge": "^1.0.0-28059208.2abef1b",
|
||||||
"@nuxtjs/eslint-module": "^4.0.2",
|
"@nuxtjs/eslint-module": "^4.1.0",
|
||||||
"@nuxtjs/tailwindcss": "^6.6.6",
|
"@nuxtjs/tailwindcss": "^6.7.0",
|
||||||
"@types/node": "^18",
|
"@types/node": "^20",
|
||||||
"@vueuse/components": "^10.1.0",
|
"@vueuse/components": "^10.1.2",
|
||||||
"@vueuse/core": "^10.1.0",
|
"@vueuse/core": "^10.1.2",
|
||||||
"@vueuse/nuxt": "^10.1.0",
|
"@vueuse/nuxt": "^10.1.2",
|
||||||
"eslint": "^8.39.0",
|
"eslint": "^8.41.0",
|
||||||
"eslint-plugin-tailwindcss": "^3.11.0",
|
"eslint-plugin-tailwindcss": "^3.12.0",
|
||||||
"nuxt": "^3.4.2",
|
"nuxt": "^3.5.0",
|
||||||
"nuxt-icon": "^0.3.3"
|
"nuxt-icon": "^0.4.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxt/eslint-config": "^0.1.1",
|
"@nuxt/eslint-config": "^0.1.1",
|
||||||
@ -30,8 +30,7 @@
|
|||||||
"@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",
|
"minecraft-server-util": "^5.4.2",
|
||||||
"mongodb": "^5.3.0",
|
"mongodb": "^5.5.0",
|
||||||
"socket.io-client": "^4.6.1",
|
"socket.io-client": "^4.6.1"
|
||||||
"surrealdb.js": "^0.6.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
web/pages/mod/server.vue
Normal file
14
web/pages/mod/server.vue
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mt-5">
|
||||||
|
Server Control
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
definePageMeta({
|
||||||
|
middleware: ["auth"],
|
||||||
|
moderator: true
|
||||||
|
})
|
||||||
|
|
||||||
|
useHead({ title: 'Server Control | Polarcraft' })
|
||||||
|
</script>
|
77
web/pages/mod/users.vue
Normal file
77
web/pages/mod/users.vue
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mt-5">
|
||||||
|
<Modal v-if="actionModal.open" :title="actionModal.title">
|
||||||
|
WIP
|
||||||
|
</Modal>
|
||||||
|
<h1 class="text-2xl font-bold text-primary">
|
||||||
|
Users
|
||||||
|
</h1>
|
||||||
|
<div class="mx-auto my-10 max-w-4xl">
|
||||||
|
<h2 class="mb-2 text-xl font-bold text-primary">User Actions</h2>
|
||||||
|
<div class="w-full rounded border-[1px] border-primary px-3 py-1 text-left">
|
||||||
|
<table class="w-full table-auto divide-y divide-neutral-500 rounded">
|
||||||
|
<tr class="border-b-2 border-primary text-gray-200">
|
||||||
|
<th class="py-1">Username</th>
|
||||||
|
<th class="py-1">Team</th>
|
||||||
|
<th class="py-1">MC Linked</th>
|
||||||
|
<th class="py-1">Actions</th>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="user in users" :key="user._id" class="text-gray-200">
|
||||||
|
<td class="py-1">{{ user.username }}</td>
|
||||||
|
<td class="py-1">{{ user.team ? teams.filter(a => a._id === user.team.id)[0].name : '-' }}</td>
|
||||||
|
<td class="py-1">{{ user.minecraft.uuid ? 'True ' : 'False' }}</td>
|
||||||
|
<td class="space-x-2 py-1">
|
||||||
|
<span v-if="currentUser.role.admin" class="rounded bg-red-700 px-2 text-red-300 hover:cursor-pointer hover:bg-red-800" @click="openModal(user, 'ban', ban(user))">Ban</span>
|
||||||
|
<span class="rounded bg-orange-700 px-2 text-orange-300 hover:cursor-pointer hover:bg-orange-800">Suspend</span>
|
||||||
|
<span class="rounded bg-yellow-700 px-2 text-yellow-300 hover:cursor-pointer hover:bg-yellow-800">Warn</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
definePageMeta({
|
||||||
|
middleware: ["auth"],
|
||||||
|
moderator: true
|
||||||
|
})
|
||||||
|
|
||||||
|
useHead({ title: 'Users | Polarcraft' })
|
||||||
|
|
||||||
|
const currentUser = useState('user')
|
||||||
|
|
||||||
|
const { data: users } = useFetch('/api/auth/getusers')
|
||||||
|
const { data: teams } = useFetch('/api/team/all')
|
||||||
|
|
||||||
|
const actionModal = ref({
|
||||||
|
open: false,
|
||||||
|
title: '',
|
||||||
|
userId: '',
|
||||||
|
func: null,
|
||||||
|
})
|
||||||
|
|
||||||
|
const openModal = (user, type, func) => {
|
||||||
|
if (type === 'ban') actionModal.value.title = 'Ban User'
|
||||||
|
if (type === 'suspend') actionModal.value.title = 'Suspend User'
|
||||||
|
if (type === 'warn') actionModal.value.title = 'Warn User'
|
||||||
|
|
||||||
|
actionModal.value.func = func
|
||||||
|
actionModal.value.userId = user._id;
|
||||||
|
actionModal.value.open = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const ban = async (user) => {
|
||||||
|
try {
|
||||||
|
const response = await $fetch(`/api/auth/user/${user._id}/ban`, {
|
||||||
|
reason: "reason"
|
||||||
|
})
|
||||||
|
|
||||||
|
user = response;
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
useToast().error('Error banning user')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,6 +1,59 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mt-5 text-primary">
|
<div class="mt-5 text-primary">
|
||||||
Player Store
|
<Modal
|
||||||
|
v-if="storeModal.open"
|
||||||
|
title="Create new store"
|
||||||
|
:delete="!storeModal.new"
|
||||||
|
@submit="submitModal"
|
||||||
|
@delete="deleteStore"
|
||||||
|
@close="storeModal.open = false"
|
||||||
|
>
|
||||||
|
<Input v-model="storeModal.name" background-class="bg-neutral-800">Store name</Input>
|
||||||
|
<div class="flex gap-x-5">
|
||||||
|
<Input v-model="storeModal.coords.x" background-class="bg-neutral-800">Coordinate X</Input>
|
||||||
|
<Input v-model="storeModal.coords.z" background-class="bg-neutral-800">Coordinate Z</Input>
|
||||||
|
</div>
|
||||||
|
<h2 class="font-bold">Items</h2>
|
||||||
|
<div class="max-h-56 space-y-3 overflow-scroll">
|
||||||
|
<div v-for="item, index in storeModal.items" :key="item.name" class="flex gap-2">
|
||||||
|
<Input v-model="item.displayName" background-class="bg-neutral-800">Name</Input>
|
||||||
|
<Input v-model="item.price" background-class="bg-neutral-800">Price per quantity</Input>
|
||||||
|
<Button type="danger" @click="storeModal.items.splice(index, 1)"><Icon size="1.5em" name="ph:trash" class="-my-2" /></Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button class="" @click="storeModal.items.push({ displayName: '', price: '' })">Add Item</Button>
|
||||||
|
</Modal>
|
||||||
|
<h1 class="pb-10 text-2xl font-bold text-primary">
|
||||||
|
Player Stores
|
||||||
|
</h1>
|
||||||
|
<div class="fixed bottom-10 right-10">
|
||||||
|
<Button class="fixed" @click="openStoreModal(true)">
|
||||||
|
Create Store
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-wrap gap-10">
|
||||||
|
<div v-for="store in stores" :key="store._id.toString()" class="h-min w-96 rounded-lg bg-neutral-800 text-gray-200 shadow relative">
|
||||||
|
<div v-if="store.ownerId === user._id" class="absolute right-5 top-5 hover:cursor-pointer" @click="openStoreModal(false, store)">
|
||||||
|
<Icon name="ph:pencil-simple" size="1.6em" />
|
||||||
|
</div>
|
||||||
|
<div class="p-5 pb-3">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<img :src="'https://api.mineatar.io/face/' + store.owner.minecraft.uuid + '?scale=3'" class="mr-2 aspect-square rounded">
|
||||||
|
{{ store.owner.username }}
|
||||||
|
</div>
|
||||||
|
<h2 class="text-2xl font-bold text-primary">
|
||||||
|
{{ store.name }}
|
||||||
|
<span class="text-sm font-medium">({{ store.coords.x }}, {{ store.coords.z }})</span>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<h2 class="ml-3 text-xl font-bold">Items</h2>
|
||||||
|
<div class="divide-y divide-neutral-600 rounded-lg bg-neutral-700 px-4 pt-2 pb-2">
|
||||||
|
<div v-for="item in store.items" :key="item.displayname" class="py-1">
|
||||||
|
<b>{{ item.displayName }}</b> for <b>{{ item.price }}</b>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -9,5 +62,97 @@ definePageMeta({
|
|||||||
middleware: ["auth"]
|
middleware: ["auth"]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const user = useState('user')
|
||||||
|
|
||||||
useHead({ title: 'Player Stores | Polarcraft' })
|
useHead({ title: 'Player Stores | Polarcraft' })
|
||||||
|
|
||||||
|
const { data: stores } = await useFetch('/api/store');
|
||||||
|
|
||||||
|
const storeModal = ref({
|
||||||
|
open: false,
|
||||||
|
name: '',
|
||||||
|
new: false,
|
||||||
|
id: '',
|
||||||
|
coords: {
|
||||||
|
x: '',
|
||||||
|
z: '',
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{ displayName: '', price: '' }
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
const openStoreModal = (newStore, store) => {
|
||||||
|
storeModal.value.open = true;
|
||||||
|
|
||||||
|
if (newStore === true) {
|
||||||
|
storeModal.value.name = '';
|
||||||
|
storeModal.value.items = [
|
||||||
|
{ displayName: '', price: '' }
|
||||||
|
];
|
||||||
|
|
||||||
|
storeModal.value.coords = { x: '', z: '' }
|
||||||
|
|
||||||
|
storeModal.value.new = true
|
||||||
|
} else {
|
||||||
|
storeModal.value.new = false
|
||||||
|
|
||||||
|
storeModal.value.items = []
|
||||||
|
store.items.forEach(item => {
|
||||||
|
storeModal.value.items.push(item);
|
||||||
|
})
|
||||||
|
|
||||||
|
storeModal.value.name = store.name
|
||||||
|
storeModal.value.id = store._id
|
||||||
|
storeModal.value.coords.x = store.coords.x
|
||||||
|
storeModal.value.coords.z = store.coords.z
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitModal = async () => {
|
||||||
|
try {
|
||||||
|
const store = await $fetch('/api/store', {
|
||||||
|
method: 'POST',
|
||||||
|
body: { name: storeModal.value.name, coords: storeModal.value.coords, items: storeModal.value.items, id: storeModal.value.id || null }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (storeModal.value.id) {
|
||||||
|
const oldStore = stores.value.filter(a => a._id === storeModal.value.id)[0]
|
||||||
|
|
||||||
|
oldStore.name = storeModal.value.name;
|
||||||
|
oldStore.coords = storeModal.value.coords;
|
||||||
|
oldStore.items = storeModal.value.items;
|
||||||
|
} else {
|
||||||
|
store.owner = user
|
||||||
|
stores.value.push(store)
|
||||||
|
}
|
||||||
|
|
||||||
|
storeModal.value.open = false
|
||||||
|
|
||||||
|
useToast().success('Succesvol store aangemaakt')
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
useToast().error(e.statusMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteStore = async () => {
|
||||||
|
try {
|
||||||
|
await $fetch('/api/store', {
|
||||||
|
method: 'DELETE',
|
||||||
|
body: { id: storeModal.value.id }
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
stores.value = stores.value.filter(a => a._id !== storeModal.value.id)
|
||||||
|
|
||||||
|
storeModal.value.open = false
|
||||||
|
useToast().success('Succesvol store verwijderd')
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
useToast().error(e.statusMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
13
web/server/api/auth/getusers.js
Normal file
13
web/server/api/auth/getusers.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const user = await getAuth(event)
|
||||||
|
|
||||||
|
if (!user.role.moderator) return createError({ statusCode: 403, statusMessage: 'Gebruiker heeft geen toegang tot alle gebruikers' })
|
||||||
|
|
||||||
|
const usersColl = db.collection('users');
|
||||||
|
|
||||||
|
const cursor = usersColl.find()
|
||||||
|
|
||||||
|
const users = await cursor.toArray()
|
||||||
|
|
||||||
|
return users
|
||||||
|
});
|
@ -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 }, teamInvites: [], role: {} } }, { 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 )
|
||||||
|
|
||||||
|
25
web/server/api/auth/user/[id]/ban.js
Normal file
25
web/server/api/auth/user/[id]/ban.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { ObjectId } from "mongodb";
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const { reason } = await readBody(event)
|
||||||
|
|
||||||
|
const currentUser = await getAuth(event)
|
||||||
|
const userId = event.context.params.id;
|
||||||
|
|
||||||
|
if (!reason) return createError({ statusCode: 400, statusMessage: 'Reason is vereist' })
|
||||||
|
if (!currentUser.role.admin) return createError({ statusCode: 403, statusMessage: 'Geen toegang om gebruiker te bannen' })
|
||||||
|
|
||||||
|
const usersColl = db.collection('users')
|
||||||
|
const user = usersColl.findOneAndUpdate({ _id: new ObjectId(userId)}, { $set: { banned: { reason: reason, date: new Date() } } })
|
||||||
|
|
||||||
|
if (!user.value) return createError({ statusCode: 500, statusMessage: 'Error tijdens het updaten van de gebruiker' })
|
||||||
|
|
||||||
|
await $fetch(config.discordHost + '/user/ban', {
|
||||||
|
method: 'POST',
|
||||||
|
body: { reason: reason, discordId: user.discord.id }
|
||||||
|
})
|
||||||
|
|
||||||
|
await sendRconCommand(`ban ${user.value.minecraft.uuid} ${reason}`)
|
||||||
|
|
||||||
|
return user
|
||||||
|
});
|
@ -1,5 +1,3 @@
|
|||||||
import { applyUsername } from "~/server/utils/auth";
|
|
||||||
|
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
const user = await getAuth(event)
|
const user = await getAuth(event)
|
||||||
|
|
||||||
|
17
web/server/api/store/index.delete.js
Normal file
17
web/server/api/store/index.delete.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { ObjectId } from "mongodb";
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const { id } = await readBody(event)
|
||||||
|
|
||||||
|
const user = await getAuth(event)
|
||||||
|
|
||||||
|
const storesColl = db.collection('stores');
|
||||||
|
|
||||||
|
const result = await storesColl.deleteOne({ _id: new ObjectId(id) })
|
||||||
|
|
||||||
|
if (result.deletedCount === 1) {
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
throw createError({ statusCode: 500, statusMessage: 'Error tijdens het verwijderen van de store' })
|
||||||
|
}
|
||||||
|
});
|
21
web/server/api/store/index.get.js
Normal file
21
web/server/api/store/index.get.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
export default defineEventHandler(async () => {
|
||||||
|
|
||||||
|
const storesColl = db.collection('stores');
|
||||||
|
|
||||||
|
const cursor = storesColl.aggregate([
|
||||||
|
{
|
||||||
|
$lookup:
|
||||||
|
{
|
||||||
|
from: "users",
|
||||||
|
localField: "ownerId",
|
||||||
|
foreignField: "_id",
|
||||||
|
as: "owner",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$unwind: "$owner",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
return await cursor.toArray()
|
||||||
|
});
|
13
web/server/api/store/index.post.js
Normal file
13
web/server/api/store/index.post.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { ObjectId } from "mongodb";
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const { coords, name, items, id } = await readBody(event)
|
||||||
|
|
||||||
|
const user = await getAuth(event)
|
||||||
|
|
||||||
|
const storesColl = db.collection('stores');
|
||||||
|
|
||||||
|
const { value: store } = await storesColl.findOneAndUpdate({ _id: id ? new ObjectId(id) : new ObjectId() }, { $set: { coords: coords, name: name, items: items, ownerId: user._id, } }, { returnDocument: 'after', upsert: true })
|
||||||
|
|
||||||
|
return store
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user