Realtime sync
This commit is contained in:
parent
f22be8d6f2
commit
5a5fa05667
@ -5,11 +5,6 @@
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css" integrity="sha384-GvrOXuhMATgEsSwCs4smul74iXGOixntILdUW9XmUC6+HX0sLNAK3q71HotJqlAn" crossorigin="anonymous">
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js" integrity="sha384-XjKyOOlGwcjNTAIQHIpgOno0Hl1YQqzUOEleOLALmuqehneUG+vnGctmUb0ZY0l8" crossorigin="anonymous"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"></script>
|
||||
<title>Dragonroll</title>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -88,6 +88,7 @@
|
||||
--chat-background: var(--c-white);
|
||||
|
||||
--color-border: var(--c-white-border);
|
||||
--color-border-soft: #a5a5a511;
|
||||
|
||||
--section-gap: 160px;
|
||||
--separator-color: #2e2e2e;
|
||||
|
@ -12,7 +12,6 @@ import VueMarkdownEditor from '@kangc/v-md-editor';
|
||||
import '@kangc/v-md-editor/lib/style/base-editor.css';
|
||||
import vuepressTheme from '@kangc/v-md-editor/lib/theme/vuepress.js';
|
||||
import '@kangc/v-md-editor/lib/theme/style/vuepress.css';
|
||||
import createKatexPlugin from '@kangc/v-md-editor/lib/plugins/katex/cdn';
|
||||
import esEs from '@kangc/v-md-editor/lib/lang/es-ES'
|
||||
|
||||
|
||||
@ -29,7 +28,6 @@ import 'prismjs/components/prism-bash';
|
||||
|
||||
VueMarkdownEditor.lang.use('es-Es', esEs);
|
||||
VueMarkdownEditor.use(vuepressTheme, { Prism });
|
||||
VueMarkdownEditor.use(createKatexPlugin());
|
||||
|
||||
const app = createApp(App).use(VueMarkdownEditor);
|
||||
app.config.globalProperties.emitter = emitter
|
||||
|
@ -20,7 +20,7 @@ function DisplayToast(color, text, duration = 1000){
|
||||
emitter.emit("toast", {color, text, duration});
|
||||
}
|
||||
|
||||
export const socket = io(backendUrl)
|
||||
const socket = io(backendUrl)
|
||||
|
||||
let currentCampaign = null;
|
||||
let currentPlayer = null;
|
||||
@ -115,6 +115,7 @@ function GetSystem(){
|
||||
}
|
||||
|
||||
export {
|
||||
socket,
|
||||
SetEmitter,
|
||||
GetEmitter,
|
||||
|
||||
|
@ -243,7 +243,6 @@ function SetupHandle(id, handle){
|
||||
|
||||
function SetResizable(id, resizable){
|
||||
let win = GetWindowWithId(id);
|
||||
console.log(win);
|
||||
win.resizable = resizable;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ import EditProfileWindow from '@/views/windows/EditProfileWindow.vue'
|
||||
import AccountSettingsWindow from '../windows/AccountSettingsWindow.vue'
|
||||
|
||||
import { Windows, ReloadRef } from '@/services/Windows';
|
||||
import DbWindow from '../windows/database/DbWindow.vue'
|
||||
import CampaignListWindow from '../windows/campaigns/CampaignListWindow.vue'
|
||||
import NewCampaignWindow from '../windows/campaigns/NewCampaignWindow.vue'
|
||||
import JoinCampaignWindow from '../windows/campaigns/JoinCampaignWindow.vue'
|
||||
@ -73,12 +72,9 @@ async function InjectSystemWindows(system){
|
||||
};
|
||||
|
||||
WindowMap = {...WindowMap, ...systemWidows};
|
||||
|
||||
console.log(WindowMap)
|
||||
}
|
||||
|
||||
InjectSystemWindows('dnd-5e')
|
||||
console.log(WindowMap);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
66
client/src/views/partials/ConceptList.vue
Normal file
66
client/src/views/partials/ConceptList.vue
Normal file
@ -0,0 +1,66 @@
|
||||
<script setup>
|
||||
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { GetCampaign } from '../../services/Dragonroll';
|
||||
import { ClearWindow, CreateWindow } from '../../services/Windows';
|
||||
|
||||
const props = defineProps(['elements']);
|
||||
|
||||
const listContainer = ref(null);
|
||||
const elements = ref([]);
|
||||
|
||||
onMounted(() => {
|
||||
watch(() => props.elements, () => {
|
||||
elements.value = props.elements;
|
||||
});
|
||||
});
|
||||
|
||||
function OpenConcept(element){
|
||||
CreateWindow('item_sheet', {
|
||||
id: 'item_sheet',
|
||||
title: 'Edit Item',
|
||||
item_id: element._id,
|
||||
close: () => ClearWindow('item_sheet')
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="list-container" ref="listContainer">
|
||||
|
||||
<div class="list-element" v-for="element in elements" :key="element._id" v-on:click.prevent="OpenConcept(element)">
|
||||
<img :src="element.info ? element.info.icon : 'icons/game-icons/ffffff/lorc/crossed-swords.svg'" class="concept-icon">
|
||||
<span class="title">{{ element.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.concept-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.list-element {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--color-border-soft);
|
||||
|
||||
|
||||
.title {
|
||||
padding-left: 10px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.list-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
@ -4,18 +4,19 @@ import { onMounted, ref, getCurrentInstance, defineExpose } from 'vue';
|
||||
import { ClearWindow, CreateChildWindow } from '../../services/Windows';
|
||||
|
||||
const image = ref(null);
|
||||
const props = defineProps(['window']);
|
||||
const props = defineProps(['window', 'done']);
|
||||
|
||||
const uuid = getCurrentInstance().uid;
|
||||
const icon = ref(null);
|
||||
const icon = ref('icons/game-icons/ffffff/lorc/crossed-swords.svg');
|
||||
const done = props.done;
|
||||
|
||||
function SelectIcon(){
|
||||
CreateChildWindow(props.window, 'icon_selector', {
|
||||
id: 'icon-selector-' + uuid,
|
||||
done: (res) => {
|
||||
icon.value = res;
|
||||
console.log(res);
|
||||
image.value.src = res.selected.path;
|
||||
icon.value = res.selected.path;
|
||||
done(res);
|
||||
ClearWindow('icon-selector-' + uuid);
|
||||
},
|
||||
close: () => {
|
||||
@ -33,7 +34,7 @@ defineExpose({
|
||||
|
||||
<template>
|
||||
<div class="icon-selector">
|
||||
<img ref="image" src="icons/sundries/books/book-red-exclamation.webp" v-on:click.prevent="SelectIcon">
|
||||
<img ref="image" :src="icon" v-on:click.prevent="SelectIcon">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -1,58 +0,0 @@
|
||||
<script setup>
|
||||
import { onMounted, onUpdated, ref } from 'vue';
|
||||
import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Windows';
|
||||
|
||||
import WindowHandle from '@/views/partials/WindowHandle.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 -->
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.window-wrapper {
|
||||
min-width: 700px;
|
||||
min-height: 630px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.splash-image {
|
||||
width: 600px;
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
align-items: left;
|
||||
flex-direction: column;
|
||||
justify-content: left;
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
label {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,9 +1,12 @@
|
||||
<script setup>
|
||||
import WindowHandle from '@/views/partials/WindowHandle.vue';
|
||||
import Api from '@/services/Api'
|
||||
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { ClearWindow, CreateWindow, ResetPosition, SetSize, SetupHandle } from '../../../services/Windows';
|
||||
import { onMounted, ref, shallowRef } from 'vue';
|
||||
import { ClearWindow, CreateWindow, ResetPosition, SetMinSize, SetResizable, SetSize, SetupHandle } from '../../../services/Windows';
|
||||
import IconButton from '@/views/partials/game/IconButton.vue'
|
||||
import ConceptList from '../../partials/ConceptList.vue';
|
||||
import { GetCampaign, socket } from '../../../services/Dragonroll';
|
||||
|
||||
const handle = ref(null);
|
||||
|
||||
@ -11,12 +14,34 @@ const props = defineProps(['data']);
|
||||
const data = props.data;
|
||||
|
||||
let id = data.id;
|
||||
const elements = shallowRef([]);
|
||||
|
||||
// SHOULD MOVE!!!
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
SetupHandle(id, handle);
|
||||
SetSize(id, {width: 700, height: 800});
|
||||
ResetPosition(id, "center");
|
||||
SetResizable(id, true);
|
||||
SetMinSize(id, {width: 350, height: 300});
|
||||
|
||||
FetchConcepts();
|
||||
|
||||
socket.on('update-concepts', () => {
|
||||
console.log("!!!");
|
||||
FetchConcepts();
|
||||
});
|
||||
});
|
||||
|
||||
function FetchConcepts(){
|
||||
Api().get('/concept/list?campaign=' + GetCampaign()._id).then(response => {
|
||||
// console.log(response.data);
|
||||
elements.value = response.data.data;
|
||||
console.log(elements);
|
||||
console.log("Updated???")
|
||||
}).catch((err) => console.log(err));
|
||||
}
|
||||
|
||||
function OpenCreateItemPrompt(){
|
||||
CreateWindow('create_item_prompt', {id: 'create_item_prompt', title: 'Create Item', close: () => ClearWindow('create_item_prompt')})
|
||||
@ -34,8 +59,10 @@ function OpenCreateItemPrompt(){
|
||||
<div class="toggler">Spells</div>
|
||||
<div class="toggler">Features</div>
|
||||
</div>
|
||||
<ConceptList :elements="elements"></ConceptList>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="fixed-bottom-buttons">
|
||||
<IconButton icon="icons/iconoir/regular/plus.svg" :action="OpenCreateItemPrompt"></IconButton>
|
||||
</div>
|
||||
@ -44,6 +71,10 @@ function OpenCreateItemPrompt(){
|
||||
|
||||
|
||||
<style scoped>
|
||||
.main-container {
|
||||
height: calc(100% - 24px);
|
||||
}
|
||||
|
||||
.toggler {
|
||||
flex-grow: 1;
|
||||
font-weight: bold;
|
||||
|
@ -27,6 +27,7 @@ function ConfirmSelection(){
|
||||
id: 'item_sheet',
|
||||
title: 'Edit Item',
|
||||
item_type: value,
|
||||
item_create: true,
|
||||
close: () => ClearWindow('item_sheet')
|
||||
});
|
||||
|
||||
|
@ -1,79 +1,91 @@
|
||||
<script setup>
|
||||
import WindowHandle from '@/views/partials/WindowHandle.vue';
|
||||
import Api from '@/services/Api'
|
||||
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { onMounted, ref, shallowRef } from 'vue';
|
||||
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
|
||||
import { CreateWindow } from '../../../../services/Windows';
|
||||
import IconSelector from '../../../partials/IconSelector.vue';
|
||||
import { AddContextMenu, HideContextMenu, ShowContextMenu } from '../../../../services/ContextMenu';
|
||||
import { GetCampaign } from '../../../../services/Dragonroll';
|
||||
const props = defineProps(['data']);
|
||||
const data = props.data;
|
||||
|
||||
const handle = ref(null);
|
||||
const item_type = ref("");
|
||||
|
||||
const rarity = ref(null);
|
||||
const weaponType = ref(null);
|
||||
const item_name = ref(null);
|
||||
const icon_selector = ref(null);
|
||||
|
||||
function GenRarities(){
|
||||
let rarities = [];
|
||||
let raritiesNames = ['', 'Common', 'Uncommon', 'Rare', 'Very Rare', 'Legendary', 'Artifact'];
|
||||
raritiesNames.forEach(name => {
|
||||
let lowerName = name.replace(/\s+/g, '-').toLowerCase();
|
||||
rarities.push({
|
||||
name: `<span class='${lowerName}'>${name}</span>`,
|
||||
action: () => {
|
||||
rarity.value.innerHTML = `<span class='important ${lowerName}'>${name}</span>`;
|
||||
HideContextMenu();
|
||||
SetParam('rarity', name);
|
||||
}
|
||||
})
|
||||
});
|
||||
return rarities;
|
||||
}
|
||||
|
||||
function GenTypes(list){
|
||||
let types = [];
|
||||
list.forEach(name => {
|
||||
types.push({
|
||||
name,
|
||||
action: () => {
|
||||
weaponType.value.innerHTML = `<span class="important">${name}</span>`;
|
||||
HideContextMenu();
|
||||
SetParam('weapon_type', name);
|
||||
}
|
||||
});
|
||||
});
|
||||
return types;
|
||||
}
|
||||
|
||||
let id = data.id;
|
||||
let concept = shallowRef({});
|
||||
let oldInfo;
|
||||
|
||||
onMounted(() => {
|
||||
SetupHandle(id, handle);
|
||||
SetSize(id, {width: 500, height: 400});
|
||||
ResetPosition(id, "center");
|
||||
|
||||
item_type.value = data.item_type;
|
||||
|
||||
const rarities = [
|
||||
{name: "⠀",
|
||||
action: () => { rarity.value.innerHTML = ""; HideContextMenu(); }
|
||||
},
|
||||
{name: "<span class='common'>Common</span>",
|
||||
action: () => { rarity.value.innerHTML = "<span class='important common'>Common</span>"; HideContextMenu(); }
|
||||
},
|
||||
{name: "<span class='uncommon'>Uncommon</span>",
|
||||
action: () => { rarity.value.innerHTML = "<span class='important uncommon'>Uncommon</span>"; HideContextMenu(); }
|
||||
},
|
||||
{name: "<span class='rare'>Rare</span>",
|
||||
action: () => { rarity.value.innerHTML = "<span class='important rare'>Rare</span>"; HideContextMenu(); }
|
||||
},
|
||||
{name: "<span class='very-rare'>Very rare</span>",
|
||||
action: () => { rarity.value.innerHTML = "<span class='important very-rare'>Very rare</span>"; HideContextMenu(); }
|
||||
},
|
||||
{name: "<span class='legendary'>Legendary</span>",
|
||||
action: () => { rarity.value.innerHTML = "<span class='important legendary'>Legendary</span>"; HideContextMenu(); }
|
||||
},
|
||||
{name: "<span class='artifact'>Artifact</span>",
|
||||
action: () => { rarity.value.innerHTML = "<span class='important artifact'>Artifact</span>"; HideContextMenu(); }
|
||||
function Upload(){
|
||||
let extraParams = "";
|
||||
if(oldInfo != concept.value.info){
|
||||
extraParams = "&fireUpdate=true";
|
||||
oldInfo = structuredClone(concept.value.info);
|
||||
console.log("MAIASIUDHSAHJ")
|
||||
}
|
||||
]
|
||||
|
||||
const weapon_types = [
|
||||
{name: "⠀",
|
||||
action: () => { weaponType.value.innerHTML = ""; HideContextMenu(); }
|
||||
},
|
||||
{name: "Melee",
|
||||
action: () => { weaponType.value.innerHTML = "<span class='important'>Melee</span>"; HideContextMenu(); }
|
||||
},
|
||||
{name: "Ranged",
|
||||
action: () => { weaponType.value.innerHTML = "<span class='important'>Ranged</span>"; HideContextMenu(); }
|
||||
},
|
||||
{name: "Martial Melee",
|
||||
action: () => { weaponType.value.innerHTML = "<span class='important'>Martial Melee</span>"; HideContextMenu(); }
|
||||
},
|
||||
{name: "Martial Ranged",
|
||||
action: () => { weaponType.value.innerHTML = "<span class='important'>Martial Ranged</span>"; HideContextMenu(); }
|
||||
},
|
||||
{name: "Natural",
|
||||
action: () => { weaponType.value.innerHTML = "<span class='important'>Natural</span>"; HideContextMenu(); }
|
||||
},
|
||||
{name: "Improvised",
|
||||
action: () => { weaponType.value.innerHTML = "<span class='important'>Improvised</span>"; HideContextMenu(); }
|
||||
},
|
||||
{name: "Siege Weapon",
|
||||
action: () => { weaponType.value.innerHTML = "<span class='important'>Siege Weapon</span>"; HideContextMenu(); }
|
||||
Api().put('/concept/update?campaign=' + GetCampaign()._id + "&id=" + concept.value._id + extraParams, {concept: concept.value}).then(response => {
|
||||
console.log(response);
|
||||
});
|
||||
}
|
||||
]
|
||||
|
||||
function SetParam(param, value){
|
||||
concept.value.info[param] = value;
|
||||
Upload();
|
||||
}
|
||||
|
||||
function IconSelected(val){
|
||||
SetParam('icon', val.selected.path);
|
||||
Upload();
|
||||
}
|
||||
|
||||
function InitValues(){
|
||||
let rarities = GenRarities();
|
||||
let weapon_types = GenTypes(["", "Melee", "Ranged", "Martial Melee", "Martial Ranged", "Natural", "Improvised", "Siege Weapon"]);
|
||||
|
||||
if(!concept.value.data) concept.value.data = {};
|
||||
if(!concept.value.info) concept.value.info = {};
|
||||
|
||||
if(concept.value.info.icon) icon_selector.value.icon = concept.value.info.icon;
|
||||
if(concept.value.info.rarity) rarity.value.innerHTML = `<span class='important ${concept.value.info.rarity.replace(/\s+/g, '-').toLowerCase()}'>${concept.value.info.rarity}</span>`;
|
||||
if(concept.value.info.weapon_type) weaponType.value.innerHTML = `<span class='important'>${concept.value.info.weapon_type}</span>`;
|
||||
|
||||
rarity.value.addEventListener("click", () => {
|
||||
ShowContextMenu(rarities)
|
||||
@ -83,11 +95,39 @@ onMounted(() => {
|
||||
weaponType.value.addEventListener("click", () => {
|
||||
ShowContextMenu(weapon_types)
|
||||
});
|
||||
AddContextMenu(weaponType.value, weapon_types)
|
||||
|
||||
weaponType.value.addEventListener("click", () => {
|
||||
AddContextMenu(weaponType.value, weapon_types);
|
||||
|
||||
item_name.value.addEventListener('blur', () => {
|
||||
concept.value.name = item_name.value.textContent;
|
||||
Upload();
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
SetupHandle(id, handle);
|
||||
SetSize(id, {width: 500, height: 400});
|
||||
ResetPosition(id, "center");
|
||||
item_type.value = data.item_type;
|
||||
|
||||
if(data.item_create){
|
||||
Api().post('/concept/create?campaign=' + GetCampaign()._id, {
|
||||
data: {
|
||||
type: data.item_type,
|
||||
name: "New " + data.item_type
|
||||
},
|
||||
}).then(response => {
|
||||
concept.value = response.data.concept;
|
||||
InitValues();
|
||||
|
||||
}).catch(err => console.log(err));
|
||||
} else {
|
||||
// Get concept
|
||||
Api().get('/concept/get?campaign=' + GetCampaign()._id + "&id=" + data.item_id).then(response => {
|
||||
concept.value = response.data.concept;
|
||||
InitValues();
|
||||
}).catch(err => console.log(err));
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
@ -99,20 +139,12 @@ onMounted(() => {
|
||||
|
||||
<div class="main-container">
|
||||
<div class="item-header">
|
||||
<IconSelector :window="id"></IconSelector>
|
||||
<IconSelector :window="id" ref="icon_selector" :done="IconSelected"></IconSelector>
|
||||
<div class="header-info">
|
||||
<h1 contenteditable="true" spellcheck="false">New Item</h1>
|
||||
<h1 contenteditable="true" spellcheck="false" ref="item_name">{{ concept.name }}</h1>
|
||||
<div class="row">
|
||||
<div class="grow subsection" ref="weaponType"></div>
|
||||
<div class="grow subsection" ref="rarity"></div>
|
||||
<!--
|
||||
<option value="none"><span></span></option>
|
||||
<option value="common"><span class="common">Common</span></option>
|
||||
<option value="uncommon"><span class="uncommon">Uncommon</span></option>
|
||||
<option value="rare"><span class="rare">Rare</span></option>
|
||||
<option value="very rare"><span class="very-rare">Very Rare</span></option>
|
||||
<option value="legendary"><span class="legendary">Legendary</span></option>
|
||||
<option value="artifact"><span class="artifact">Artifact</span></option>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
21
server/config/middleware.js
Normal file
21
server/config/middleware.js
Normal file
@ -0,0 +1,21 @@
|
||||
const Campaign = require("../models/Campaign");
|
||||
const CampaignUser = require("../models/CampaignUser");
|
||||
|
||||
function hasCampaign(req, res, next){
|
||||
Campaign.findById(req.query.campaign).lean().then((campaign) => {
|
||||
CampaignUser.findOne({campaign, user: req.user}).lean().then((campaignUser) => {
|
||||
if(!campaignUser) {
|
||||
res.json({status: "error", msg: "not-found"})
|
||||
return;
|
||||
}
|
||||
req.cu = campaignUser;
|
||||
req.campaign = campaign;
|
||||
req.room = req.query.campaign;
|
||||
next();
|
||||
}).catch((err) => res.json({status: "error", err}));
|
||||
}).catch((err) => res.json({status: "error", err}));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hasCampaign
|
||||
}
|
15
server/io/socket.js
Normal file
15
server/io/socket.js
Normal file
@ -0,0 +1,15 @@
|
||||
let ioInstance;
|
||||
|
||||
function setIo(io){
|
||||
if(!ioInstance) ioInstance = io;
|
||||
}
|
||||
|
||||
function getIo() {
|
||||
return ioInstance;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setIo,
|
||||
getIo,
|
||||
ioInstance
|
||||
}
|
@ -2,10 +2,10 @@ const mongoose = require("mongoose");
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const ConceptSchema = new Schema({
|
||||
name: {type: String, required: true},
|
||||
system: {type: String, required: true},
|
||||
type: { type: String },
|
||||
data: { type: Object },
|
||||
name: {type: String, required: true, default: "New Concept"},
|
||||
type: { type: String, required: true, default: "Concept" },
|
||||
info: { type: Object }, // For preview only
|
||||
data: { type: Object }, // Advanced item
|
||||
book: {type: mongoose.Types.ObjectId, ref: "Book"},
|
||||
campaign: {type: mongoose.Types.ObjectId, ref: "Campaign"},
|
||||
});
|
||||
|
@ -2,7 +2,6 @@ const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
const passport = require('passport');
|
||||
const rateLimitMiddleware = require("../config/rate-limiter");
|
||||
|
||||
const Campaign = require("../models/Campaign");
|
||||
const CampaignUser = require("../models/CampaignUser");
|
||||
@ -13,8 +12,7 @@ const upload = require("../config/storage");
|
||||
router.post('/register', passport.authenticate('jwt', {session: false}), rateLimitMiddleware, (req, res) => {
|
||||
});
|
||||
*/
|
||||
|
||||
router.post('/create', passport.authenticate('jwt', {session: false}), rateLimitMiddleware, (req, res) => {
|
||||
router.post('/create', (req, res) => {
|
||||
let {
|
||||
name,
|
||||
system
|
||||
@ -47,7 +45,7 @@ router.post('/create', passport.authenticate('jwt', {session: false}), rateLimit
|
||||
}).catch((err) => {res.json({status: "error", msg: "internal"})});
|
||||
});
|
||||
|
||||
router.post('/join', passport.authenticate('jwt', {session: false}), rateLimitMiddleware, (req, res) => {
|
||||
router.post('/join', (req, res) => {
|
||||
let {
|
||||
invite_code
|
||||
} = req.body;
|
||||
@ -82,16 +80,16 @@ router.post('/join', passport.authenticate('jwt', {session: false}), rateLimitMi
|
||||
}).catch(err => res.json({status: "error", msg: "internal"}))
|
||||
});
|
||||
|
||||
router.get('/list', passport.authenticate('jwt', {session: false}), (req, res) => {
|
||||
CampaignUser.find({user: req.user}).populate("campaign").then((data) => {
|
||||
router.get('/list', (req, res) => {
|
||||
CampaignUser.find({user: req.user}).populate("campaign").lean().then((data) => {
|
||||
res.json(data);
|
||||
console.log(data);
|
||||
return;
|
||||
}).catch((err) => res.json({status: "error", msg: "internal"}));
|
||||
});
|
||||
|
||||
router.get('/players', passport.authenticate('jwt', {session: false}), (req, res) => {
|
||||
Campaign.findById(req.query.campaign).then((campaign) => {
|
||||
router.get('/players', (req, res) => {
|
||||
Campaign.findById(req.query.campaign).lean().then((campaign) => {
|
||||
CampaignUser.find({campaign}).populate('user').then((data) => {
|
||||
console.log("djskajdk")
|
||||
console.log(data);
|
||||
|
@ -11,24 +11,24 @@ const Character = require('../models/Character');
|
||||
const upload = require("../config/storage");
|
||||
|
||||
// Get characters from a campaign
|
||||
router.get('/list', passport.authenticate('jwt', {session: false}), (req, res) => {
|
||||
router.get('/list', (req, res) => {
|
||||
|
||||
});
|
||||
|
||||
// Character info
|
||||
router.post('/create', passport.authenticate('jwt', {session: false}), rateLimitMiddleware, (req, res) => {
|
||||
router.post('/create', rateLimitMiddleware, (req, res) => {
|
||||
|
||||
});
|
||||
|
||||
router.delete('/delete', passport.authenticate('jwt', {session: false}), rateLimitMiddleware, (req, res) => {
|
||||
router.delete('/delete', rateLimitMiddleware, (req, res) => {
|
||||
|
||||
});
|
||||
|
||||
router.get('/get', passport.authenticate('jwt', {session: false}), (req, res) => {
|
||||
router.get('/get', (req, res) => {
|
||||
|
||||
});
|
||||
|
||||
router.put('/update', passport.authenticate('jwt', {session: false}), (req, res) => {
|
||||
router.put('/update', (req, res) => {
|
||||
|
||||
});
|
||||
|
||||
|
72
server/routes/concept.js
Normal file
72
server/routes/concept.js
Normal file
@ -0,0 +1,72 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
|
||||
const passport = require('passport');
|
||||
|
||||
const Campaign = require("../models/Campaign");
|
||||
const CampaignUser = require("../models/CampaignUser");
|
||||
const Concept = require('../models/Concept');
|
||||
const { hasCampaign } = require('../config/middleware');
|
||||
const { getIo } = require('../io/socket');
|
||||
|
||||
const io = getIo();
|
||||
|
||||
router.get('/list', hasCampaign, (req, res) => {
|
||||
const campaign = req.campaign;
|
||||
Concept.find({campaign}).select('-data').lean().then(data => {
|
||||
res.json({status: "ok", data});
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/create', hasCampaign, (req, res) => {
|
||||
const campaign = req.campaign;
|
||||
let data = req.body.data;
|
||||
|
||||
if(!(data.type && data.name)) {
|
||||
res.json({status: "error", msg: "args"});
|
||||
return;
|
||||
}
|
||||
|
||||
let concept = new Concept({campaign, type: data.type, name: data.name});
|
||||
concept.save().then(concept => {
|
||||
io.to(req.room).emit('update-concepts');
|
||||
res.json({status: "ok", concept});
|
||||
})
|
||||
});
|
||||
|
||||
router.delete('/delete', hasCampaign, (req, res) => {
|
||||
const campaign = req.campaign;
|
||||
let id = req.query.id;
|
||||
if(!id) {
|
||||
res.json({status: "error", msg: "args"});
|
||||
return;
|
||||
}
|
||||
|
||||
Concept.deleteOne({_id: id, campaign}).then(() => {
|
||||
io.to(req.room).emit('update-concepts');
|
||||
res.json({status: "ok"});
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/get', hasCampaign, (req, res) => {
|
||||
const campaign = req.campaign;
|
||||
let id = req.query.id;
|
||||
|
||||
Concept.findOne({_id: id, campaign}).lean().then(concept => {
|
||||
res.json({status: "ok", concept});
|
||||
});
|
||||
});
|
||||
|
||||
router.put('/update', hasCampaign, (req, res) => {
|
||||
const campaign = req.campaign;
|
||||
let id = req.query.id;
|
||||
|
||||
Concept.findOneAndUpdate({_id: id, campaign}, req.body.concept).then(result => {
|
||||
console.log(req.room)
|
||||
if(req.query.fireUpdate) io.to(req.room).emit('update-concepts');
|
||||
io.to(req.room).emit('update-concept', id);
|
||||
res.json({status: "ok"});
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
@ -10,17 +10,11 @@ const Map = require("../models/Map");
|
||||
const fs = require('fs');
|
||||
|
||||
const upload = require("../config/storage");
|
||||
const { hasCampaign } = require('../config/middleware');
|
||||
|
||||
router.post('/create-resource', upload.single("image"), passport.authenticate('jwt', {session: false}), (req, res) => {
|
||||
router.post('/create-resource', hasCampaign, upload.single("image"), (req, res) => {
|
||||
const imageName = req.file.filename;
|
||||
|
||||
Campaign.findById(req.query.campaign).then((campaign) => {
|
||||
CampaignUser.findOne({campaign, user: req.user}).then((data) => {
|
||||
if(!data) {
|
||||
res.json({status: "error", msg: "not-found"})
|
||||
fs.unlink(imageName);
|
||||
return;
|
||||
}
|
||||
const data = req.cu;
|
||||
|
||||
if(data.is_dm){
|
||||
res.json({
|
||||
@ -28,23 +22,17 @@ router.post('/create-resource', upload.single("image"), passport.authenticate('j
|
||||
data: imageName
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
res.json({status: "error", msg: "not-dm"})
|
||||
}
|
||||
|
||||
res.json({status: "error", msg: "not-dm"})
|
||||
fs.unlink(imageName);
|
||||
return;
|
||||
}).catch((err) => res.json({status: "error", msg: "not-found"}));
|
||||
}).catch((err) => res.json({status: "error", err}));
|
||||
});
|
||||
|
||||
// rateLimitMiddleware?
|
||||
router.post('/create', passport.authenticate('jwt', {session: false}), (req, res) => {
|
||||
Campaign.findById(req.body.campaign).then((campaign) => {
|
||||
CampaignUser.findOne({campaign, user: req.user}).then((data) => {
|
||||
if(!data) {
|
||||
res.json({status: "error", msg: "not-found"})
|
||||
return;
|
||||
}
|
||||
router.post('/create', hasCampaign, (req, res) => {
|
||||
const data = req.cu;
|
||||
const campaign = req.campaign;
|
||||
|
||||
if(data.is_dm){
|
||||
let mapData = req.body.data;
|
||||
@ -63,20 +51,13 @@ router.post('/create', passport.authenticate('jwt', {session: false}), (req, res
|
||||
} else res.json({status: "error", msg: "args"})
|
||||
return;
|
||||
}
|
||||
}).catch((err) => res.json({status: "error", msg: "not-found"}));
|
||||
}).catch((err) => res.json({status: "error", err}));
|
||||
});
|
||||
|
||||
router.post('/update', passport.authenticate('jwt', {session: false}), (req, res) => {
|
||||
Campaign.findById(req.query.campaign).then((campaign) => {
|
||||
CampaignUser.findOne({campaign, user: req.user}).then((data) => {
|
||||
if(!data) {
|
||||
res.json({status: "error", msg: "not-found"})
|
||||
return;
|
||||
}
|
||||
router.post('/update', hasCampaign, (req, res) => {
|
||||
const data = req.cu;
|
||||
const campaign = req.campaign;
|
||||
|
||||
if(data.is_dm){
|
||||
console.log("Ab");
|
||||
let mapData = req.body.data;
|
||||
if(mapData){
|
||||
console.log("Map data:");
|
||||
@ -90,31 +71,22 @@ router.post('/update', passport.authenticate('jwt', {session: false}), (req, res
|
||||
} else res.json({status: "error", msg: "args"})
|
||||
return;
|
||||
}
|
||||
}).catch((err) => res.json({status: "error", msg: "not-found"}));
|
||||
}).catch((err) => res.json({status: "error", err}));
|
||||
});
|
||||
|
||||
router.get('/list', passport.authenticate('jwt', {session: false}), (req, res) => {
|
||||
Campaign.findById(req.query.campaign).then((campaign) => {
|
||||
CampaignUser.findOne({campaign, user: req.user}).then((data) => {
|
||||
if(!data) {
|
||||
res.json({status: "error", msg: "not-found"})
|
||||
return;
|
||||
}
|
||||
router.get('/list', hasCampaign, (req, res) => {
|
||||
const campaign = req.campaign;
|
||||
|
||||
Map.find({campaign}).then(data => {
|
||||
res.json({status: "ok", data});
|
||||
return;
|
||||
}).catch(err => res.json({status: "error", msg: "internal"}));
|
||||
}).catch((err) => res.json({status: "error", msg: "not-found"}));
|
||||
}).catch((err) => res.json({status: "error", err}));
|
||||
});
|
||||
|
||||
router.get('/get', passport.authenticate('jwt', {session: false}), (req, res) => {
|
||||
router.get('/get', (req, res) => {
|
||||
|
||||
});
|
||||
|
||||
router.delete('/delete', passport.authenticate('jwt', {session: false}), (req, res) => {
|
||||
router.delete('/delete', (req, res) => {
|
||||
|
||||
});
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
const express = require('express');
|
||||
const http = require('http')
|
||||
const socketIo = require('socket.io');
|
||||
|
||||
const app = express();
|
||||
const cookieParser = require('cookie-parser');
|
||||
const bodyParser = require('body-parser');
|
||||
@ -11,67 +10,75 @@ const path = require('path');
|
||||
const morgan = require('morgan');
|
||||
const cors = require('cors');
|
||||
const passport = require('passport');
|
||||
|
||||
const server = http.createServer(app);
|
||||
const io = socketIo(server, {
|
||||
cors: {
|
||||
origin: '*',
|
||||
}
|
||||
});
|
||||
|
||||
const PORT = 8081;
|
||||
|
||||
const config = JSON.parse(fs.readFileSync("config.json"));
|
||||
|
||||
// SET CONSTANTS
|
||||
const PORT = 8081;
|
||||
global.appRoot = path.resolve(__dirname);
|
||||
|
||||
|
||||
var mongo_final_ip = "";
|
||||
|
||||
let mongo_final_ip = "";
|
||||
console.log("Production? " + !process.env.DEBUG);
|
||||
if(process.env.DEBUG){
|
||||
mongo_final_ip = "mongodb://" + config.mongo_ip_debug + "/dragonroll";
|
||||
} else {
|
||||
mongo_final_ip = "mongodb://" + config.mongo_ip + "/dragonroll";
|
||||
}
|
||||
console.log(mongo_final_ip)
|
||||
console.log("Db ip: " + mongo_final_ip)
|
||||
|
||||
// CONFIGURE SOCKET IO
|
||||
const socket = require('./io/socket')
|
||||
const io = socketIo(server, {
|
||||
cors: {
|
||||
origin: '*',
|
||||
}
|
||||
});
|
||||
socket.setIo(io);
|
||||
|
||||
// CONNECT TO MONGODB
|
||||
mongoose.connect(mongo_final_ip).then(() => {
|
||||
console.log("Connected to database");
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
// PASSPORT
|
||||
app.use(morgan('tiny'));
|
||||
|
||||
app.use(passport.initialize());
|
||||
require('./config/passport')(passport);
|
||||
|
||||
// Carpeta publica
|
||||
// PUBLIC
|
||||
app.use("/public", express.static(__dirname + '/public'));
|
||||
// app.use("/.well-known", express.static(__dirname + '/.well-known'));
|
||||
app.use('/public', express.static('uploads'));
|
||||
|
||||
// IDk per a què serveix això
|
||||
// JSON LIMIT EXPRESS
|
||||
app.use(express.json({limit: '50mb'}));
|
||||
app.use(express.urlencoded({
|
||||
extended : false,
|
||||
limit: '50mb'
|
||||
}));
|
||||
|
||||
// CORS
|
||||
app.use(cookieParser());
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
app.use(cors());
|
||||
|
||||
// Routes (/ només)
|
||||
// ROUTES (NO AUTH)
|
||||
app.use('/user', require('./routes/user'));
|
||||
|
||||
// AUTH
|
||||
checkAuth = passport.authenticate('jwt', {session: false});
|
||||
app.use(checkAuth);
|
||||
|
||||
// ROUTES WITH AUTH
|
||||
app.use('/campaign', require('./routes/campaign'));
|
||||
app.use('/maps', require('./routes/map'))
|
||||
app.use('/concept', require('./routes/concept'))
|
||||
// GET localhost:8081/concept/list
|
||||
|
||||
// SETUP IO
|
||||
require('./io/campaign')(socket.getIo());
|
||||
|
||||
app.use('/public', express.static('uploads'));
|
||||
|
||||
require('./io/campaign')(io);
|
||||
|
||||
// app.use('/users', require('./routes/users'));
|
||||
// LISTEN
|
||||
server.listen(PORT, () => {
|
||||
console.log("Dragonroll backend started");
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user