This commit is contained in:
BinarySandia04 2024-09-28 01:41:47 +02:00
parent ede69a2a7a
commit 8581fb9314
21 changed files with 194 additions and 32 deletions

View File

@ -1,5 +1,6 @@
const Campaign = require("../models/Campaign"); const Campaign = require("../models/Campaign");
const CampaignUser = require("../models/CampaignUser"); const CampaignUser = require("../models/CampaignUser");
const User = require("../models/User");
function hasCampaign(req, res, next){ function hasCampaign(req, res, next){
Campaign.findById(req.query.campaign).lean().then((campaign) => { Campaign.findById(req.query.campaign).lean().then((campaign) => {
@ -16,11 +17,17 @@ function hasCampaign(req, res, next){
}).catch((err) => res.json({status: "error", err})); }).catch((err) => res.json({status: "error", err}));
} }
function hasUser(req, res, next){ function isAdmin(req, res, next){
User.findOne(req.user).lean().then((user) => {
if(user.admin){
next();
return;
}
res.json({status: "error", msg: "unauthorized"});
}).catch((err) => res.json({status: "error", err}));
} }
module.exports = { module.exports = {
hasCampaign, hasCampaign,
hasUser isAdmin
} }

17
backend/routes/admin.js Normal file
View File

@ -0,0 +1,17 @@
const express = require('express');
const router = express.Router();
const { isAdmin } = require('../config/middleware');
const User = require("../models/User");
router.get('/users', isAdmin, (req, res) => {
console.log("HJDSHAKJDHKH")
User.find({}).then((users) => {
console.log("HJDSHAKJDHKH2")
res.json({
users
});
});
})
module.exports = router;

View File

@ -1,10 +1,6 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const passport = require('passport');
const Campaign = require("../models/Campaign");
const CampaignUser = require("../models/CampaignUser");
const Concept = require('../models/Concept'); const Concept = require('../models/Concept');
const { hasCampaign } = require('../config/middleware'); const { hasCampaign } = require('../config/middleware');
const { getIo } = require('../io/socket'); const { getIo } = require('../io/socket');

View File

@ -73,6 +73,7 @@ app.use(checkAuth);
app.use('/campaign', require('./routes/campaign')); app.use('/campaign', require('./routes/campaign'));
app.use('/maps', require('./routes/map')) app.use('/maps', require('./routes/map'))
app.use('/concept', require('./routes/concept')) app.use('/concept', require('./routes/concept'))
app.use('/admin', require('./routes/admin'))
// GET localhost:8081/concept/list // GET localhost:8081/concept/list
// SETUP IO // SETUP IO

View File

@ -221,6 +221,11 @@ button:active {
width: 100%; width: 100%;
} }
.document.centered {
text-align: center;
justify-content: center;
}
.document.item { .document.item {
text-align: center; text-align: center;
width: 220px; width: 220px;

View File

@ -23,11 +23,14 @@ async function FetchPlugins(){
name: pluginData.name, name: pluginData.name,
_id: pluginName, _id: pluginName,
info: { info: {
name: pluginData.name,
description: pluginData.description,
authors: pluginData.authors,
version: pluginData.version,
} }
}); });
import(/* @vite-ignore */ `../../plugins/${pluginName}/${pluginData.entrypoint}`).then(module => { import(/* @vite-ignore */ `../../plugins/${pluginName}/${pluginData.client.entrypoint}`).then(module => {
module.Main({ module.Main({
Dragonroll, Dragonroll,
Chat, Chat,

View File

@ -29,6 +29,7 @@ import IconSelectorWindow from '@/views/windows/selectors/IconSelectorWindow.vue
import DatabaseWindow from '@/views/windows/game/DatabaseWindow.vue' import DatabaseWindow from '@/views/windows/game/DatabaseWindow.vue'
import AccountManagementWindow from '@/views/windows/settings/AccountManagementWindow.vue' import AccountManagementWindow from '@/views/windows/settings/AccountManagementWindow.vue'
import PluginManagementWindow from '@/views/windows/settings/PluginManagementWindow.vue' import PluginManagementWindow from '@/views/windows/settings/PluginManagementWindow.vue'
import PluginWindow from '../views/windows/settings/PluginWindow.vue';
let windowMap = { let windowMap = {
test: ExampleWindow, test: ExampleWindow,
@ -56,7 +57,8 @@ let windowMap = {
icon_selector: IconSelectorWindow, icon_selector: IconSelectorWindow,
database: DatabaseWindow, database: DatabaseWindow,
plugin_management: PluginManagementWindow, plugin_management: PluginManagementWindow,
account_management: AccountManagementWindow account_management: AccountManagementWindow,
plugin_window: PluginWindow
}; };
async function InjectWindow(plugin, window_type, window_component){ async function InjectWindow(plugin, window_type, window_component){

View File

@ -0,0 +1,22 @@
<script setup>
const props = defineProps(['title', 'img']);
</script>
<template>
<div class="document centered">
<h1>{{props.title}}</h1>
<img :src="props.img" class="big-icon">
<br>
<slot></slot>
</div>
</template>
<style lang="scss" scoped>
.big-icon {
height: 80px;
width: 80px;
border: 1px solid var(--color-border);
padding: 16px;
margin:auto;
}
</style>

View File

@ -11,15 +11,15 @@ const elementDiv = ref(null);
const tooltipContainer = ref(null); const tooltipContainer = ref(null);
const icon = ref("icons/game-icons/ffffff/lorc/crossed-swords.svg") const icon = ref("icons/game-icons/ffffff/lorc/crossed-swords.svg")
function updateElement(){ async function updateElement(){
element.value = props.element; element.value = props.element;
// Do whatever // Do whatever
let desc = element.value.info.description; let desc = element.value.info.description;
desc = desc ? marked.parse(desc) : ''; desc = desc ? marked.parse(desc) : '';
if(props.icon) icon.value = props.icon(element.value); if(props.icon) icon.value = await props.icon(element.value);
let tooltip = props.tooltip(element.value); let tooltip = await props.tooltip(element.value);
if(tooltip) AddTooltip(tooltipContainer.value, tooltip); if(tooltip) AddTooltip(tooltipContainer.value, tooltip);
} }

View File

@ -52,9 +52,9 @@ function onLeave(el, done) {
<ConceptEntry class="list-element" v-for="(element, index) in elements" <ConceptEntry class="list-element" v-for="(element, index) in elements"
:key="element._id" :key="element._id"
:element="element" :element="element"
:context="() => ContextElement(element)" :context="async () => await ContextElement(element)"
:tooltip="(el) => TooltipElement(el)" :tooltip="async (el) => await TooltipElement(el)"
:icon="(el) => IconElement(el)" :icon="async (el) => await IconElement(el)"
v-on:click.prevent="OpenElement(element)" v-on:click.prevent="OpenElement(element)"
:data-index="index"></ConceptEntry> :data-index="index"></ConceptEntry>
</TransitionGroup> </TransitionGroup>

View File

@ -39,7 +39,6 @@ function OpenCreateItemPrompt(){
function OpenConcept(element){ function OpenConcept(element){
console.log(`${GetCampaignModuleName()}/item_sheet`);
CreateWindow(`${GetCampaignModuleName()}/item_sheet`, { CreateWindow(`${GetCampaignModuleName()}/item_sheet`, {
id: 'item_sheet_' + element._id, id: 'item_sheet_' + element._id,
title: 'Edit Item', title: 'Edit Item',
@ -49,7 +48,6 @@ function OpenConcept(element){
} }
function ElementContext(element){ function ElementContext(element){
console.log(element);
return [ return [
{name: "Open"}, {name: "Open"},
{name: "Delete"} {name: "Delete"}

View File

@ -1,8 +1,13 @@
<script setup> <script setup>
import { onMounted, ref } from 'vue'; import { onMounted, ref, shallowRef } from 'vue';
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows'; import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
import Api from '@/services/Api'
import IconButton from '@/views/partials/game/IconButton.vue'
import WindowHandle from '@/views/partials/WindowHandle.vue'; import WindowHandle from '@/views/partials/WindowHandle.vue';
import ConceptList from '../../partials/ConceptList.vue';
import { backendUrl } from '../../../services/BackendURL';
const handle = ref(null); const handle = ref(null);
@ -11,13 +16,32 @@ const data = props.data;
let id = data.id; let id = data.id;
const test = ref(null) const elements = shallowRef([]);
onMounted(() => { onMounted(() => {
SetupHandle(id, handle); SetupHandle(id, handle);
SetSize(id, {width: 500, height: 380}); SetSize(id, {width: 500, height: 380});
ResetPosition(id, "center"); ResetPosition(id, "center");
Api().get('/admin/users').then(response => {
let users = response.data.users;
elements.value = [];
users.forEach(user => {
elements.value.push({
name: user.username,
_id: user._id,
info: {
name: user.username
}
})
});
}).catch((err) => console.log(err));
}); });
async function ElementIcon(element){
let response = await Api().get('/user/retrieve-avatar?username=' + element.name);
if(response.data.image) return backendUrl + "public/" + response.data.image;
}
</script> </script>
@ -26,8 +50,14 @@ onMounted(() => {
<WindowHandle :window="id" ref="handle"></WindowHandle> <WindowHandle :window="id" ref="handle"></WindowHandle>
<!-- Body --> <!-- Body -->
<div ref="test"></div> <ConceptList
:elements="elements"
:icon="ElementIcon"
></ConceptList>
<div class="fixed-bottom-buttons">
<IconButton icon="/icons/iconoir/regular/plus.svg" :action="OpenCreateItemPrompt"></IconButton>
</div>
</div> </div>
</template> </template>
@ -37,6 +67,14 @@ onMounted(() => {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.fixed-bottom-buttons {
position: absolute;
bottom: 10px;
right: 10px;
z-index: 2;
display: flex;
}
</style> </style>

View File

@ -5,7 +5,7 @@ import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
import WindowHandle from '@/views/partials/WindowHandle.vue'; import WindowHandle from '@/views/partials/WindowHandle.vue';
import ConceptList from '../../partials/ConceptList.vue'; import ConceptList from '../../partials/ConceptList.vue';
import { _GetPlugins } from '../../../services/Plugins'; import { _GetPlugins } from '../../../services/Plugins';
import { SetMinSize, SetResizable } from '../../../services/Windows'; import { ClearWindow, CreateChildWindow, SetMinSize, SetResizable } from '../../../services/Windows';
const handle = ref(null); const handle = ref(null);
@ -32,6 +32,16 @@ onMounted(() => {
function GetPluginIcon(plugin){ function GetPluginIcon(plugin){
return `/plugins/${plugin._id}/icon.png`; return `/plugins/${plugin._id}/icon.png`;
} }
function OpenPlugin(plugin){
CreateChildWindow(id, '', {
type: 'plugin_window',
id: 'plugin-window-' + plugin._id,
title: plugin.name,
plugin,
close: () => ClearWindow('plugin-window-' + plugin._id)
})
}
</script> </script>
@ -43,6 +53,7 @@ function GetPluginIcon(plugin){
<ConceptList <ConceptList
:elements="elements" :elements="elements"
:icon="GetPluginIcon" :icon="GetPluginIcon"
:open="OpenPlugin"
></ConceptList> ></ConceptList>
</div> </div>
</template> </template>

View File

@ -0,0 +1,42 @@
<script setup>
import { onMounted, ref } from 'vue';
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
import WindowHandle from '@/views/partials/WindowHandle.vue';
import BigIconTemplate from '../../partials/BigIconTemplate.vue';
const handle = ref(null);
const props = defineProps(['data']);
const data = props.data;
let id = data.id;
onMounted(() => {
SetupHandle(id, handle);
SetSize(id, {width: 500, height: 380});
ResetPosition(id, "center");
});
</script>
<template>
<div class="window-wrapper" :id="'window-wrapper-' + id">
<WindowHandle :window="id" ref="handle"></WindowHandle>
<!-- Body -->
<BigIconTemplate :title="data.plugin.name" :img="`plugins/${data.plugin._id}/icon.png`">
</BigIconTemplate>
</div>
</template>
<style lang="scss" scoped>
.window-wrapper {
display: flex;
align-items: center;
}
</style>

View File

@ -14,7 +14,7 @@ function Main(Api){
"name": "Aran Roig" "name": "Aran Roig"
} }
], ],
"version": "1.0.0", "version": "0.1",
"color": "#e92026" "color": "#e92026"
}); });

View File

@ -1,4 +0,0 @@
{
"name": "Dnd 5e System",
"entrypoint": "main.js"
}

View File

@ -4,6 +4,7 @@ import WindowHandle from '@/views/partials/WindowHandle.vue';
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows'; import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
import { ClearWindow, CreateWindow } from '@/services/Windows'; import { ClearWindow, CreateWindow } from '@/services/Windows';
import { GetCampaignModuleName } from '../../../../client/src/services/Campaign';
const props = defineProps(['data']); const props = defineProps(['data']);
const data = props.data; const data = props.data;
@ -23,7 +24,7 @@ function ConfirmSelection(){
if(!selected) return; if(!selected) return;
let value = selected.value; let value = selected.value;
CreateWindow('item_sheet', { CreateWindow(`${GetCampaignModuleName()}/item_sheet`, {
id: 'item_sheet', id: 'item_sheet',
title: 'Edit Item', title: 'Edit Item',
item_type: value, item_type: value,

View File

@ -0,0 +1,13 @@
{
"name": "Dnd 5e System",
"description": "This plugin provides the Dnd 5e module",
"authors": [
{
"name": "Aran Roig"
}
],
"version": "0.1",
"client": {
"entrypoint": "main.js"
}
}

View File

@ -1,4 +0,0 @@
{
"name": "Dragonroll example plugin",
"entrypoint": "main.js"
}

View File

@ -0,0 +1,13 @@
{
"name": "Dragonroll example plugin",
"description": "This is an example plugin to help you getting started with the Dragonroll API",
"authors": [
{
"name": "Aran Roig"
}
],
"version": "0.1",
"client": {
"entrypoint": "main.js"
}
}

View File

@ -94,6 +94,7 @@ console.log("Updated Locales")
for(let j = 0; j < plugins.length; j++){ for(let j = 0; j < plugins.length; j++){
if(fs.existsSync(`./plugins/${plugins[j]}/client/`)){ if(fs.existsSync(`./plugins/${plugins[j]}/client/`)){
fs.cpSync(`./plugins/${plugins[j]}/client/`, `./client/plugins/${plugins[j]}`, {recursive: true}); fs.cpSync(`./plugins/${plugins[j]}/client/`, `./client/plugins/${plugins[j]}`, {recursive: true});
fs.copyFileSync(`./plugins/${plugins[j]}/plugin.json`, `./client/plugins/${plugins[j]}/plugin.json`);
} }
if(fs.existsSync(`./plugins/${plugins[j]}/public/`)){ if(fs.existsSync(`./plugins/${plugins[j]}/public/`)){