diff --git a/.gitignore b/.gitignore
index e6e7ad24..80f1cfe5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,9 @@ client/public/plugins/
# Backend
backend/plugins/
+# Docs
+docs/
+
# local env files
.env.local
.env.*.local
diff --git a/README.md b/README.md
index 7b8d0d7c..86fde3df 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-
-
+
+
diff --git a/backend/services/api.js b/backend/services/api.js
new file mode 100644
index 00000000..1334c0f1
--- /dev/null
+++ b/backend/services/api.js
@@ -0,0 +1,24 @@
+const mongoose = require("mongoose");
+const Schema = mongoose.Schema;
+
+class BackendApi {
+ /**
+ * Plugin
+ * @param {plugin} Plugin instance
+ */
+ constructor(plugin){
+ this.plugin = plugin;
+ }
+
+ createRoute(){
+
+ }
+
+ createModel(name, schema){
+ return mongoose.model(name, new Schema(schema))
+ }
+};
+
+module.exports = {
+ BackendApi
+}
\ No newline at end of file
diff --git a/backend/services/plugins.js b/backend/services/plugins.js
index 5c9f8c92..7e0cb209 100644
--- a/backend/services/plugins.js
+++ b/backend/services/plugins.js
@@ -1,6 +1,6 @@
const fs = require('fs');
const path = require('path')
-const Api = {}
+const Api = require('./api').Api
const basePath = path.resolve(__dirname, '../')
console.log(basePath)
@@ -25,7 +25,7 @@ function init(){
// Execute main
Object.keys(plugins).forEach(k => {
- plugins[k].Main(Api)
+ plugins[k].Main(new Api(k))
})
}
diff --git a/build.sh b/build.sh
new file mode 100755
index 00000000..f5a47307
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+node prebuild.js
+npm run generate-docs
+cp -r media docs/dragonroll/1.0.0/
\ No newline at end of file
diff --git a/client/src/services/Api.js b/client/src/services/Api.js
index b9948726..ef480e9a 100644
--- a/client/src/services/Api.js
+++ b/client/src/services/Api.js
@@ -1,13 +1,23 @@
-import axios from 'axios';
+import * as Dragonroll from "@/services/Dragonroll"
+import * as Chat from "@/services/Chat"
+import * as ContextMenu from "@/services/ContextMenu"
+import * as Map from "@/services/Map"
+import * as Modules from "@/services/Modules"
+import * as Sound from "@/services/Sound"
+import * as Tooltip from "@/services/Tooltip"
+import * as Windows from "@/services/Windows"
-import { backendUrl } from './BackendURL';
+const Api = {
+ Dragonroll,
+ Chat,
+ ContextMenu,
+ Map,
+ Modules,
+ Sound,
+ Tooltip,
+ Windows
+}
-export default () => {
- return axios.create({
- baseURL: backendUrl,
- headers: {
- 'Authorization': "Bearer " + localStorage.getItem('token'),
- "Access-Control-Allow-Origin": "*",
- }
- });
+export {
+ Api
}
\ No newline at end of file
diff --git a/client/src/services/Campaign.js b/client/src/services/Campaign.js
index a867db3d..81f39db0 100644
--- a/client/src/services/Campaign.js
+++ b/client/src/services/Campaign.js
@@ -6,7 +6,7 @@ import { GetUser } from "./User";
import { chat } from './Chat';
import { ClearAll, CreateWindow } from './Windows';
-import Api from '@/services/Api';
+import Server from '@/services/Server';
import { GetCampaign } from './Dragonroll';
let _currentCampaign = null;
@@ -37,7 +37,7 @@ function DisplayCampaign(data = _currentCampaign){
}
function UpdateCampaignData(data){
- Api().put('/campaign/update?campaign=' + GetCampaign()._id, {campaign: data}).then(response => {
+ Server().put('/campaign/update?campaign=' + GetCampaign()._id, {campaign: data}).then(response => {
});
}
diff --git a/client/src/services/Data.js b/client/src/services/Data.js
index 9801d585..15f921bd 100644
--- a/client/src/services/Data.js
+++ b/client/src/services/Data.js
@@ -1,4 +1,4 @@
-import Api from '@/services/Api'
+import Server from '@/services/Server'
import { GetCampaign } from "./Dragonroll";
import { socket } from './Socket';
import { reactive } from 'vue';
@@ -12,7 +12,7 @@ function InitData(){
}
function FetchConcepts(){
- Api().get('/concept/list?campaign=' + GetCampaign()._id).then(response => {
+ Server().get('/concept/list?campaign=' + GetCampaign()._id).then(response => {
data.value.concepts = response.data.data;
}).catch((err) => console.log(err));
}
@@ -27,7 +27,7 @@ socket.on('update-concepts', () => {
});
let GetConcepts = () => data.value.concepts;
-let GetConcept = (id) => Api().get('/concept/get?campaign=' + GetCampaign()._id + "&id=" + id)
+let GetConcept = (id) => Server().get('/concept/get?campaign=' + GetCampaign()._id + "&id=" + id)
export {
diff --git a/client/src/services/Map.js b/client/src/services/Map.js
index 505193e2..f094162a 100644
--- a/client/src/services/Map.js
+++ b/client/src/services/Map.js
@@ -1,6 +1,6 @@
import { initCustomFormatter, ref, toRaw } from 'vue';
-import Api from '@/services/Api'
+import Server from '@/services/Server'
import { _SendMap, GetCampaign } from './Dragonroll';
import { backendUrl } from './BackendURL';
import { socket } from './Socket';
@@ -213,7 +213,7 @@ function GetMap(id){
function UpdateMapList(){
return new Promise((resolve, reject) => {
- Api().get('/maps/list?campaign=' + GetCampaign()._id).then(response => {
+ Server().get('/maps/list?campaign=' + GetCampaign()._id).then(response => {
mapList.value = response.data.data;
resolve();
}).catch((err) => console.log(err));
@@ -237,7 +237,7 @@ function RenameMap(id, new_title){
}
function SaveMap(id){
- Api().post('/maps/update?campaign=' + GetCampaign()._id + "&map=" + id, {data: currentMap}).then(response => {
+ Server().post('/maps/update?campaign=' + GetCampaign()._id + "&map=" + id, {data: currentMap}).then(response => {
console.log("Map updated");
}).catch(err => console.log(err));
}
@@ -263,7 +263,7 @@ function UploadResource(image){
const formData = new FormData();
formData.append("image", dataURLtoFile(image.src));
- Api().post('/maps/create-resource?campaign=' + GetCampaign()._id, formData, {
+ Server().post('/maps/create-resource?campaign=' + GetCampaign()._id, formData, {
headers: { "Content-Type": "multipart/form-data"}
}).then(response => {
resolve(response.data.data);
@@ -272,7 +272,7 @@ function UploadResource(image){
}
function CreateMap(){
- Api().post('/maps/create', {
+ Server().post('/maps/create', {
campaign: GetCampaign()._id,
data: currentMap,
}).then(response => {
diff --git a/client/src/services/Plugins.js b/client/src/services/Plugins.js
index b4503c23..fac74277 100644
--- a/client/src/services/Plugins.js
+++ b/client/src/services/Plugins.js
@@ -1,13 +1,5 @@
import { GetPluginPaths } from "./Resources"
-
-import * as Dragonroll from "@/services/Dragonroll"
-import * as Chat from "@/services/Chat"
-import * as ContextMenu from "@/services/ContextMenu"
-import * as Map from "@/services/Map"
-import * as Modules from "@/services/Modules"
-import * as Sound from "@/services/Sound"
-import * as Tooltip from "@/services/Tooltip"
-import * as Windows from "@/services/Windows"
+import { Api } from '@/services/Api'
let pluginInfo = []
@@ -31,16 +23,7 @@ async function FetchPlugins(){
});
import(/* @vite-ignore */ `../../plugins/${pluginName}/${pluginData.client.entrypoint}`).then(module => {
- module.Main({
- Dragonroll,
- Chat,
- ContextMenu,
- Map,
- Modules,
- Sound,
- Tooltip,
- Windows
- });
+ module.Main(Api);
})
}
}
diff --git a/client/src/services/Server.js b/client/src/services/Server.js
new file mode 100644
index 00000000..b9948726
--- /dev/null
+++ b/client/src/services/Server.js
@@ -0,0 +1,13 @@
+import axios from 'axios';
+
+import { backendUrl } from './BackendURL';
+
+export default () => {
+ return axios.create({
+ baseURL: backendUrl,
+ headers: {
+ 'Authorization': "Bearer " + localStorage.getItem('token'),
+ "Access-Control-Allow-Origin": "*",
+ }
+ });
+}
\ No newline at end of file
diff --git a/client/src/services/User.js b/client/src/services/User.js
index 85f2da91..b2f0e38e 100644
--- a/client/src/services/User.js
+++ b/client/src/services/User.js
@@ -1,5 +1,5 @@
import { ref } from 'vue';
-import Api from '@/services/Api'
+import Server from '@/services/Server'
const UserStatus = ref(0);
@@ -20,7 +20,7 @@ function SetUser(token){
}
async function HasAdmin(){
- let response = await Api().get('/user/has-admin');
+ let response = await Server().get('/user/has-admin');
return response.data.status != "init";
}
@@ -29,7 +29,7 @@ function SetUserSetting(key, value){
let user = GetUser()
if(!user.settings) user.settings = {};
user.settings[key] = value;
- Api().post('/user/update-settings', {settings: user.settings}).then(response => {
+ Server().post('/user/update-settings', {settings: user.settings}).then(response => {
resolve(response.data.settings);
});
});
@@ -37,7 +37,7 @@ function SetUserSetting(key, value){
function GetUserSetting(key){
return new Promise((resolve, reject) => {
- Api().get('/user/get-settings').then(response => {
+ Server().get('/user/get-settings').then(response => {
if(response.data.settings)
resolve(response.data.settings[key]);
else resolve(undefined);
diff --git a/client/src/views/HomeView.vue b/client/src/views/HomeView.vue
index ebb8889f..4ceabea1 100644
--- a/client/src/views/HomeView.vue
+++ b/client/src/views/HomeView.vue
@@ -5,7 +5,7 @@ const { t } = useI18n()
import { onMounted } from 'vue';
import WindowManager from '@/views/managers/WindowManager.vue'
-import Api from '@/services/Api'
+import Server from '@/services/Server'
import { CreateWindow } from '@/services/Windows'
import { GetUser, HasAdmin, LoadUser } from '@/services/User.js'
import { DisplayToast, SetEmitter } from '@/services/Dragonroll';
@@ -35,7 +35,7 @@ async function DisplayFirstWindow(){
// Check if we have a link
if(route.query.setupCode){
// Let's try to activate it
- Api().get('/user/verify-setup?code=' + route.query.setupCode).then(res => {
+ Server().get('/user/verify-setup?code=' + route.query.setupCode).then(res => {
if(res.data.code){
// Yep exists
CreateWindow('setup_account', {
diff --git a/client/src/views/partials/CampaignEntry.vue b/client/src/views/partials/CampaignEntry.vue
index c7a07ba0..10f87181 100644
--- a/client/src/views/partials/CampaignEntry.vue
+++ b/client/src/views/partials/CampaignEntry.vue
@@ -2,7 +2,7 @@
import { onMounted, ref } from 'vue';
-import Api from '@/services/Api'
+import Server from '@/services/Server'
import { AddSound } from '../../services/Sound';
import { ConnectToCampaign, DisplayCampaign } from '../../services/Campaign';
diff --git a/client/src/views/partials/EditUserPartial.vue b/client/src/views/partials/EditUserPartial.vue
index 7640ccb9..4a0bdbc2 100644
--- a/client/src/views/partials/EditUserPartial.vue
+++ b/client/src/views/partials/EditUserPartial.vue
@@ -2,7 +2,7 @@
import { onMounted, ref } from 'vue';
import { GetUser, LogoutUser } from '@/services/User'
-import Api from '@/services/Api'
+import Server from '@/services/Server'
import useEmitter from '@/services/Emitter';
import { ClearWindows, CreateWindow, CreateChildWindow, ClearWindow } from '../../services/Windows';
@@ -14,7 +14,7 @@ username.value = GetUser().username;
function retrieveAvatar(){
let userAvatarDisplay = document.getElementById("upload-image");
- Api().get('/user/retrieve-avatar?username=' + GetUser().username).then((response) => {
+ Server().get('/user/retrieve-avatar?username=' + GetUser().username).then((response) => {
if(response.data.image) userAvatarDisplay.src = backendUrl + "public/" + response.data.image;
}).catch((err) => console.log("Internal error"));
}
@@ -53,7 +53,7 @@ onMounted(() => {
formData.append("image", image);
- Api().post('/user/upload-avatar', formData, {
+ Server().post('/user/upload-avatar', formData, {
headers: { "Content-Type": "multipart/form-data" }
}).then((response) => {
retrieveAvatar();
diff --git a/client/src/views/partials/PlayerEntry.vue b/client/src/views/partials/PlayerEntry.vue
index 742f8ca3..dbd60c0c 100644
--- a/client/src/views/partials/PlayerEntry.vue
+++ b/client/src/views/partials/PlayerEntry.vue
@@ -1,6 +1,6 @@