Merge branch 'master' into dev/webapp-master-update
6
.github/workflows/master_build.yml
vendored
|
@ -29,7 +29,7 @@ jobs:
|
|||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest, macOS-latest, ubuntu-18.04]
|
||||
os: [windows-latest, macOS-10.15, ubuntu-18.04]
|
||||
# build_type: [full, client]
|
||||
build_type: [full]
|
||||
include:
|
||||
|
@ -59,12 +59,12 @@ jobs:
|
|||
echo "CMAKE_EXTRA=-DBUILD_TOOLS:BOOLEAN=FALSE -DHIFI_PYTHON_EXEC:FILEPATH=$(which python3)" >> $GITHUB_ENV
|
||||
fi
|
||||
# Mac build variables
|
||||
if [ "${{ matrix.os }}" = "macOS-latest" ]; then
|
||||
if [ "${{ matrix.os }}" = "macOS-10.15" ]; then
|
||||
echo "PYTHON_EXEC=python3" >> $GITHUB_ENV
|
||||
echo "ZIP_COMMAND=zip" >> $GITHUB_ENV
|
||||
echo "ZIP_ARGS=-r" >> $GITHUB_ENV
|
||||
echo "INSTALLER_EXT=dmg" >> $GITHUB_ENV
|
||||
echo "CMAKE_EXTRA=-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=OFF -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -G Xcode" >> $GITHUB_ENV
|
||||
echo "CMAKE_EXTRA=-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=OFF -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DOPENSSL_LIBRARIES=/usr/local/opt/openssl/lib -G Xcode" >> $GITHUB_ENV
|
||||
echo "::set-output name=symbols_archive::${BUILD_NUMBER}-${{ matrix.build_type }}-mac-symbols.zip"
|
||||
echo "APP_TARGET_NAME=Vircadia" >> $GITHUB_ENV
|
||||
fi
|
||||
|
|
12
.github/workflows/pr_build.yml
vendored
|
@ -36,9 +36,9 @@ jobs:
|
|||
include:
|
||||
- os: windows-latest
|
||||
build_type: full
|
||||
- os: macOS-latest
|
||||
- os: macOS-10.15
|
||||
build_type: full
|
||||
- os: macOS-latest
|
||||
- os: macOS-10.15
|
||||
build_type: client
|
||||
- os: ubuntu-18.04
|
||||
build_type: full
|
||||
|
@ -81,13 +81,13 @@ jobs:
|
|||
fi
|
||||
fi
|
||||
# Mac build variables
|
||||
if [ "${{ matrix.os }}" = "macOS-latest" ]; then
|
||||
if [ "${{ matrix.os }}" = "macOS-10.15" ]; then
|
||||
echo "PYTHON_EXEC=python3" >> $GITHUB_ENV
|
||||
echo "INSTALLER_EXT=dmg" >> $GITHUB_ENV
|
||||
if [ "${{ matrix.build_type }}" = "full" ]; then
|
||||
echo "CMAKE_EXTRA=-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=OFF -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -G Xcode" >> $GITHUB_ENV
|
||||
echo "CMAKE_EXTRA=-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=OFF -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DOPENSSL_LIBRARIES=/usr/local/opt/openssl/lib -G Xcode" >> $GITHUB_ENV
|
||||
else
|
||||
echo "CMAKE_EXTRA=-DCLIENT_ONLY=1 -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=OFF -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -G Xcode" >> $GITHUB_ENV
|
||||
echo "CMAKE_EXTRA=-DCLIENT_ONLY=1 -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=OFF -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DOPENSSL_LIBRARIES=/usr/local/opt/openssl/lib -G Xcode" >> $GITHUB_ENV
|
||||
fi
|
||||
echo "APP_TARGET_NAME=Vircadia" >> $GITHUB_ENV
|
||||
fi
|
||||
|
@ -163,7 +163,7 @@ jobs:
|
|||
if: always()
|
||||
shell: bash
|
||||
run: |
|
||||
if [ "${{ matrix.os }}" == "macOS-latest" ]; then
|
||||
if [ "${{ matrix.os }}" == "macOS-10.15" ]; then
|
||||
TAR=gtar
|
||||
else
|
||||
TAR=tar
|
||||
|
|
|
@ -1062,7 +1062,7 @@ void AvatarMixer::parseDomainServerSettings(const QJsonObject& domainSettings) {
|
|||
|
||||
static const QString AVATAR_WHITELIST_OPTION = "avatar_whitelist";
|
||||
_slaveSharedData.skeletonURLWhitelist = avatarMixerGroupObject[AVATAR_WHITELIST_OPTION]
|
||||
.toString().split(',', QString::KeepEmptyParts);
|
||||
.toString().split(',', Qt::KeepEmptyParts);
|
||||
|
||||
static const QString REPLACEMENT_AVATAR_OPTION = "replacement_avatar";
|
||||
_slaveSharedData.skeletonReplacementURL = avatarMixerGroupObject[REPLACEMENT_AVATAR_OPTION]
|
||||
|
|
9
domain-server/resources/web/web-new/.editorconfig
Normal file
|
@ -0,0 +1,9 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
9
domain-server/resources/web/web-new/.eslintignore
Normal file
|
@ -0,0 +1,9 @@
|
|||
/dist
|
||||
/src-bex/www
|
||||
/src-capacitor
|
||||
/src-cordova
|
||||
/.quasar
|
||||
/node_modules
|
||||
.eslintrc.js
|
||||
babel.config.js
|
||||
/src-ssr
|
112
domain-server/resources/web/web-new/.eslintrc.js
Normal file
|
@ -0,0 +1,112 @@
|
|||
const { resolve } = require('path');
|
||||
module.exports = {
|
||||
// https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy
|
||||
// This option interrupts the configuration hierarchy at this file
|
||||
// Remove this if you have an higher level ESLint config file (it usually happens into a monorepos)
|
||||
root: true,
|
||||
|
||||
// https://eslint.vuejs.org/user-guide/#how-to-use-custom-parser
|
||||
// Must use parserOptions instead of "parser" to allow vue-eslint-parser to keep working
|
||||
// `parser: 'vue-eslint-parser'` is already included with any 'plugin:vue/**' config and should be omitted
|
||||
parserOptions: {
|
||||
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#configuration
|
||||
// https://github.com/TypeStrong/fork-ts-checker-webpack-plugin#eslint
|
||||
// Needed to make the parser take into account 'vue' files
|
||||
extraFileExtensions: ['.vue'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
project: resolve(__dirname, './tsconfig.json'),
|
||||
tsconfigRootDir: __dirname,
|
||||
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
|
||||
sourceType: 'module' // Allows for the use of imports
|
||||
},
|
||||
|
||||
env: {
|
||||
browser: true
|
||||
},
|
||||
|
||||
// Rules order is important, please avoid shuffling them
|
||||
extends: [
|
||||
// Base ESLint recommended rules
|
||||
// 'eslint:recommended',
|
||||
|
||||
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#usage
|
||||
// ESLint typescript rules
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
// consider disabling this class of rules if linting takes too long
|
||||
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||
|
||||
// Uncomment any of the lines below to choose desired strictness,
|
||||
// but leave only one uncommented!
|
||||
// See https://eslint.vuejs.org/rules/#available-rules
|
||||
'plugin:vue/vue3-essential', // Priority A: Essential (Error Prevention)
|
||||
// 'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability)
|
||||
// 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead)
|
||||
|
||||
'standard'
|
||||
|
||||
],
|
||||
|
||||
plugins: [
|
||||
// required to apply rules which need type information
|
||||
'@typescript-eslint',
|
||||
|
||||
// https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-file
|
||||
// required to lint *.vue files
|
||||
'vue',
|
||||
|
||||
],
|
||||
|
||||
globals: {
|
||||
ga: 'readonly', // Google Analytics
|
||||
cordova: 'readonly',
|
||||
__statics: 'readonly',
|
||||
__QUASAR_SSR__: 'readonly',
|
||||
__QUASAR_SSR_SERVER__: 'readonly',
|
||||
__QUASAR_SSR_CLIENT__: 'readonly',
|
||||
__QUASAR_SSR_PWA__: 'readonly',
|
||||
process: 'readonly',
|
||||
Capacitor: 'readonly',
|
||||
chrome: 'readonly'
|
||||
},
|
||||
|
||||
// add your custom rules here
|
||||
rules: {
|
||||
// allow async-await
|
||||
'generator-star-spacing': 'off',
|
||||
// allow paren-less arrow functions
|
||||
'arrow-parens': 'off',
|
||||
'one-var': 'off',
|
||||
'no-void': 'off',
|
||||
'multiline-ternary': 'off',
|
||||
'quote-props': 'off',
|
||||
|
||||
'import/first': 'off',
|
||||
'import/namespace': 'error',
|
||||
'import/default': 'error',
|
||||
'import/export': 'error',
|
||||
'import/extensions': 'off',
|
||||
'import/no-unresolved': 'off',
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
'prefer-promise-reject-errors': 'off',
|
||||
'indent': ["error", 4],
|
||||
'semi': ["error", "always"],
|
||||
|
||||
// TypeScript
|
||||
quotes: ['warn', 'double', { avoidEscape: true }],
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
|
||||
// TypeScript -> Remove these when we start using TypeScript in the project.
|
||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'@typescript-eslint/no-unsafe-call': 'off',
|
||||
'@typescript-eslint/unbound-method': 'off',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'off',
|
||||
'@typescript-eslint/no-floating-promises': 'off',
|
||||
'@typescript-eslint/restrict-template-expressions': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'@typescript-eslint/no-unsafe-return': 'off',
|
||||
|
||||
// allow debugger during development only
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
|
||||
}
|
||||
}
|
33
domain-server/resources/web/web-new/.gitignore
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
.DS_Store
|
||||
.thumbs.db
|
||||
node_modules
|
||||
|
||||
# Quasar core related directories
|
||||
.quasar
|
||||
# /dist
|
||||
|
||||
# Cordova related directories and files
|
||||
/src-cordova/node_modules
|
||||
/src-cordova/platforms
|
||||
/src-cordova/plugins
|
||||
/src-cordova/www
|
||||
|
||||
# Capacitor related directories and files
|
||||
/src-capacitor/www
|
||||
/src-capacitor/node_modules
|
||||
|
||||
# BEX related directories and files
|
||||
/src-bex/www
|
||||
/src-bex/js/core
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
8
domain-server/resources/web/web-new/.postcssrc.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
// to edit target browsers: use "browserslist" field in package.json
|
||||
require('autoprefixer')
|
||||
]
|
||||
}
|
12
domain-server/resources/web/web-new/.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
|
||||
"octref.vetur"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"hookyqr.beautify",
|
||||
"dbaeumer.jshint",
|
||||
"ms-vscode.vscode-typescript-tslint-plugin"
|
||||
]
|
||||
}
|
7
domain-server/resources/web/web-new/.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"vetur.validation.template": false,
|
||||
"vetur.format.enable": false,
|
||||
"eslint.validate": ["javascript", "javascriptreact", "typescript", "vue"],
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"vetur.experimental.templateInterpolationService": true
|
||||
}
|
33
domain-server/resources/web/web-new/README.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
# Vircadia Domain Dashboard (vircadia-domain-dashboard)
|
||||
|
||||
The Domain dashboard for Vircadia virtual worlds.
|
||||
|
||||
## Maintainer Instructions
|
||||
|
||||
If you have made changes to the dashboard, you must build it and commit those built files. It is also necessary to build it if you wish to have your changes reflected in a packaged Domain server.
|
||||
|
||||
## Install the Dependencies
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### Start the Dashboard in Development Mode (hot-code reloading, error reporting, etc.)
|
||||
```bash
|
||||
quasar dev
|
||||
```
|
||||
|
||||
### Lint the Files
|
||||
```bash
|
||||
npm run lint
|
||||
```
|
||||
|
||||
## Build the Dashboard
|
||||
|
||||
This automatically places the compiled dashboard into the right directory (`/dist/spa`) to be used by the Domain server after it is packaged.
|
||||
|
||||
```bash
|
||||
quasar build
|
||||
```
|
||||
|
||||
### Customize the configuration
|
||||
See [Configuring quasar.conf.js](https://v2.quasar.dev/quasar-cli/quasar-conf-js).
|
15
domain-server/resources/web/web-new/babel.config.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
/* eslint-env node */
|
||||
|
||||
module.exports = api => {
|
||||
return {
|
||||
presets: [
|
||||
[
|
||||
'@quasar/babel-preset-app',
|
||||
api.caller(caller => caller && caller.target === 'node')
|
||||
? { targets: { node: 'current' } }
|
||||
: {}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
1
domain-server/resources/web/web-new/dist/spa/css/885.684a1d9d.css
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
#firstTimeWizardContainer[data-v-01471642]{animation:firstTimeWizardContainerFadeIn-01471642 5s;-webkit-animation:firstTimeWizardContainerFadeIn-01471642 5s;-moz-animation:firstTimeWizardContainerFadeIn-01471642 5s;-o-animation:firstTimeWizardContainerFadeIn-01471642 5s;-ms-animation:firstTimeWizardContainerFadeIn-01471642 5s;background-color:#000000bf}@keyframes firstTimeWizardContainerFadeIn-01471642{0%{background-color:#0000}to{background-color:#000000bf}}.welcome[data-v-01471642]{color:#fff}.wizardCard[data-v-01471642]{color:#fff}.mainWizardStepper[data-v-01471642],.wizardCard[data-v-01471642]{background:none!important;box-shadow:none!important}[data-v-01471642] .q-stepper__header{display:none!important}[data-v-01471642] .q-panel{overflow:hidden!important}.q-dialog__inner div[data-v-01471642]{border:none!important;box-shadow:none!important}
|
0
domain-server/resources/web/web-new/dist/spa/css/app.31d6cfe0.css
vendored
Normal file
6
domain-server/resources/web/web-new/dist/spa/css/vendor.2ba81df8.css
vendored
Normal file
BIN
domain-server/resources/web/web-new/dist/spa/favicon.ico
vendored
Normal file
After Width: | Height: | Size: 71 KiB |
BIN
domain-server/resources/web/web-new/dist/spa/fonts/KFOkCnqEu92Fr1MmgVxIIzQ.9391e6e2.woff
vendored
Normal file
BIN
domain-server/resources/web/web-new/dist/spa/fonts/KFOlCnqEu92Fr1MmEU9fBBc-.ddd11dab.woff
vendored
Normal file
BIN
domain-server/resources/web/web-new/dist/spa/fonts/KFOlCnqEu92Fr1MmSU5fBBc-.877b9231.woff
vendored
Normal file
BIN
domain-server/resources/web/web-new/dist/spa/fonts/KFOlCnqEu92Fr1MmWUlfBBc-.0344cc3c.woff
vendored
Normal file
BIN
domain-server/resources/web/web-new/dist/spa/fonts/KFOlCnqEu92Fr1MmYUtfBBc-.b555d228.woff
vendored
Normal file
BIN
domain-server/resources/web/web-new/dist/spa/fonts/KFOmCnqEu92Fr1Mu4mxM.9b78ea3b.woff
vendored
Normal file
BIN
domain-server/resources/web/web-new/dist/spa/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.53e02ee0.woff
vendored
Normal file
BIN
domain-server/resources/web/web-new/dist/spa/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.6a798765.woff2
vendored
Normal file
BIN
domain-server/resources/web/web-new/dist/spa/icons/favicon-128x128.png
vendored
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
domain-server/resources/web/web-new/dist/spa/icons/favicon-16x16.png
vendored
Normal file
After Width: | Height: | Size: 871 B |
BIN
domain-server/resources/web/web-new/dist/spa/icons/favicon-32x32.png
vendored
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
domain-server/resources/web/web-new/dist/spa/icons/favicon-96x96.png
vendored
Normal file
After Width: | Height: | Size: 10 KiB |
1
domain-server/resources/web/web-new/dist/spa/index.html
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
<!DOCTYPE html><html><head><title>Vircadia Domain Dashboard</title><meta charset=utf-8><meta name=description content="The Domain dashboard for Vircadia virtual worlds."><meta name=format-detection content="telephone=no"><meta name=msapplication-tap-highlight content=no><meta name=viewport content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width"><link rel=icon type=image/png sizes=128x128 href=icons/favicon-128x128.png><link rel=icon type=image/png sizes=96x96 href=icons/favicon-96x96.png><link rel=icon type=image/png sizes=32x32 href=icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=icons/favicon-16x16.png><link rel=icon type=image/ico href=favicon.ico><script defer src=js/vendor.f7426f3d.js></script><script defer src=js/app.d7a0143e.js></script><link href=css/vendor.2ba81df8.css rel=stylesheet><link href=css/app.31d6cfe0.css rel=stylesheet></head><body><div id=q-app></div></body></html>
|
1
domain-server/resources/web/web-new/dist/spa/js/197.1d65bbb2.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
"use strict";(self["webpackChunkvircadia_domain_dashboard"]=self["webpackChunkvircadia_domain_dashboard"]||[]).push([[197],{7197:(t,a,n)=>{n.r(a),n.d(a,{default:()=>m});var e=n(3673);const i={id:"firstTimeWizardContainer"};function s(t,a,n,s,o,r){const u=(0,e.up)("router-view"),h=(0,e.up)("q-page-container"),d=(0,e.up)("q-layout");return(0,e.wg)(),(0,e.j4)(d,{id:"vantaBG",view:"hHh lpR fFf"},{default:(0,e.w5)((()=>[(0,e.Wm)(h,null,{default:(0,e.w5)((()=>[(0,e._)("div",i,[(0,e.Wm)(u)])])),_:1})])),_:1})}n(71);var o=n(3991);const r=(0,e.aZ)({name:"FirstTimeWizard",data(){return{vantaBG:null,vantaRings:null,refreshVantaTimeout:null,DELAY_REFRESH_VANTA:500}},async mounted(){window.THREE=o,this.vantaRings=(await n.e(736).then(n.t.bind(n,5160,23))).default,this.initVanta(),visualViewport.addEventListener("resize",this.onResize)},methods:{onResize(){this.refreshVantaTimeout&&clearTimeout(this.refreshVantaTimeout),this.refreshVantaTimeout=setTimeout((()=>{this.initVanta(),this.refreshVantaTimeout=null}),this.DELAY_REFRESH_VANTA)},initVanta(){this.vantaBG&&this.vantaBG.destroy(),this.vantaBG=this.vantaRings({el:"#vantaBG",mouseControls:!1,touchControls:!1,gyroControls:!1,minHeight:200,minWidth:200,scale:1,scaleMobile:1,color:0})}},beforeUnmount(){this.vantaBG&&this.vantaBG.destroy()}});var u=n(4899),h=n(2652),d=n(7518),l=n.n(d);r.render=s;const m=r;l()(r,"components",{QLayout:u.Z,QPageContainer:h.Z})}}]);
|
1
domain-server/resources/web/web-new/dist/spa/js/264.e2c73bef.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
"use strict";(self["webpackChunkvircadia_domain_dashboard"]=self["webpackChunkvircadia_domain_dashboard"]||[]).push([[264],{9264:(a,n,d)=>{d.r(n),d.d(n,{default:()=>i});var e=d(3673);function r(a,n,d,r,s,i){return(0,e.wg)(),(0,e.iD)("h1",null,"Test")}const s=(0,e.aZ)({name:"Index"});s.render=r;const i=s}}]);
|
1
domain-server/resources/web/web-new/dist/spa/js/870.0b04c7bb.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
"use strict";(self["webpackChunkvircadia_domain_dashboard"]=self["webpackChunkvircadia_domain_dashboard"]||[]).push([[870],{6870:(e,t,n)=>{n.r(t),n.d(t,{default:()=>h});var a=n(3673);const o={class:"fullscreen bg-blue text-white text-center q-pa-md flex flex-center"},s=(0,a._)("div",{style:{"font-size":"30vh"}}," 404 ",-1),l=(0,a._)("div",{class:"text-h2",style:{opacity:".4"}}," Oops. Nothing here... ",-1);function c(e,t,n,c,r,i){const d=(0,a.up)("q-btn");return(0,a.wg)(),(0,a.iD)("div",o,[(0,a._)("div",null,[s,l,(0,a.Wm)(d,{class:"q-mt-xl",color:"white","text-color":"blue",unelevated:"",to:"/",label:"Go Home","no-caps":""})])])}const r=(0,a.aZ)({name:"Error404"});var i=n(8240),d=n(7518),u=n.n(d);r.render=c;const h=r;u()(r,"components",{QBtn:i.Z})}}]);
|
1
domain-server/resources/web/web-new/dist/spa/js/885.c283608c.js
vendored
Normal file
1
domain-server/resources/web/web-new/dist/spa/js/app.d7a0143e.js
vendored
Normal file
27
domain-server/resources/web/web-new/dist/spa/js/vendor.f7426f3d.js
vendored
Normal file
9777
domain-server/resources/web/web-new/package-lock.json
generated
Normal file
52
domain-server/resources/web/web-new/package.json
Normal file
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"name": "vircadia-domain-dashboard",
|
||||
"version": "0.0.1",
|
||||
"description": "The Domain dashboard for Vircadia virtual worlds.",
|
||||
"productName": "Vircadia Domain Dashboard",
|
||||
"author": "Kalila L. <somnilibertas@gmail.com>",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "eslint --ext .js,.ts,.vue ./",
|
||||
"lint-fix": "eslint --ext .js,.ts,.vue ./ --fix",
|
||||
"test": "echo \"No test specified\" && exit 0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@quasar/extras": "^1.0.0",
|
||||
"axios": "^0.21.1",
|
||||
"core-js": "^3.6.5",
|
||||
"js-sha256": "^0.9.0",
|
||||
"quasar": "^2.0.0",
|
||||
"three": "^0.132.2",
|
||||
"vanta": "^0.5.21",
|
||||
"vuex": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.13.14",
|
||||
"@quasar/app": "^3.0.0",
|
||||
"@types/node": "^12.20.21",
|
||||
"@typescript-eslint/eslint-plugin": "^4.16.1",
|
||||
"@typescript-eslint/parser": "^4.16.1",
|
||||
"eslint": "^7.14.0",
|
||||
"eslint-config-standard": "^16.0.2",
|
||||
"eslint-plugin-import": "^2.19.1",
|
||||
"eslint-plugin-node": "^11.0.0",
|
||||
"eslint-plugin-promise": "^5.1.0",
|
||||
"eslint-plugin-vue": "^7.0.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"last 10 Chrome versions",
|
||||
"last 10 Firefox versions",
|
||||
"last 4 Edge versions",
|
||||
"last 7 Safari versions",
|
||||
"last 8 Android versions",
|
||||
"last 8 ChromeAndroid versions",
|
||||
"last 8 FirefoxAndroid versions",
|
||||
"last 10 iOS versions",
|
||||
"last 5 Opera versions"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.22.1",
|
||||
"npm": ">= 6.13.4",
|
||||
"yarn": ">= 1.21.1"
|
||||
}
|
||||
}
|
BIN
domain-server/resources/web/web-new/public/favicon.ico
Normal file
After Width: | Height: | Size: 71 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 871 B |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 10 KiB |
233
domain-server/resources/web/web-new/quasar.conf.js
Normal file
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* This file runs in a Node context (it's NOT transpiled by Babel), so use only
|
||||
* the ES6 features that are supported by your Node version. https://node.green/
|
||||
*/
|
||||
|
||||
// Configuration for your app
|
||||
// https://v2.quasar.dev/quasar-cli/quasar-conf-js
|
||||
|
||||
/* eslint-env node */
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const { configure } = require("quasar/wrappers");
|
||||
|
||||
module.exports = configure(function (ctx) {
|
||||
return {
|
||||
// https://v2.quasar.dev/quasar-cli/supporting-ts
|
||||
supportTS: {
|
||||
tsCheckerConfig: {
|
||||
eslint: {
|
||||
enabled: true,
|
||||
files: "./src/**/*.{ts,tsx,js,jsx,vue}"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli/prefetch-feature
|
||||
// preFetch: true,
|
||||
|
||||
// app boot file (/src/boot)
|
||||
// --> boot files are part of "main.js"
|
||||
// https://v2.quasar.dev/quasar-cli/boot-files
|
||||
boot: [
|
||||
"axios"
|
||||
],
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css
|
||||
css: [
|
||||
"app.scss"
|
||||
],
|
||||
|
||||
// https://github.com/quasarframework/quasar/tree/dev/extras
|
||||
extras: [
|
||||
// 'ionicons-v4',
|
||||
// 'mdi-v5',
|
||||
// 'fontawesome-v5',
|
||||
// 'eva-icons',
|
||||
// 'themify',
|
||||
// 'line-awesome',
|
||||
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
|
||||
|
||||
"roboto-font", // optional, you are not bound to it
|
||||
"material-icons" // optional, you are not bound to it
|
||||
],
|
||||
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli/quasar-conf-js#Property%3A-build
|
||||
build: {
|
||||
vueRouterMode: "hash", // available values: 'hash', 'history'
|
||||
|
||||
// transpile: false,
|
||||
|
||||
// Add dependencies for transpiling with Babel (Array of string/regex)
|
||||
// (from node_modules, which are by default not transpiled).
|
||||
// Applies only if "transpile" is set to true.
|
||||
// transpileDependencies: [],
|
||||
|
||||
// rtl: true, // https://v2.quasar.dev/options/rtl-support
|
||||
// preloadChunks: true,
|
||||
// showProgress: false,
|
||||
// gzip: true,
|
||||
// analyze: true,
|
||||
|
||||
// Options below are automatically set depending on the env, set them if you want to override
|
||||
// extractCSS: false,
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli/handling-webpack
|
||||
// "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain
|
||||
chainWebpack (/* chain */) {
|
||||
//
|
||||
}
|
||||
},
|
||||
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli/quasar-conf-js#Property%3A-devServer
|
||||
devServer: {
|
||||
https: false,
|
||||
port: 8080,
|
||||
open: true // opens browser window automatically
|
||||
},
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli/quasar-conf-js#Property%3A-framework
|
||||
framework: {
|
||||
config: {
|
||||
dark: "auto"
|
||||
},
|
||||
|
||||
// iconSet: 'material-icons', // Quasar icon set
|
||||
// lang: 'en-US', // Quasar language pack
|
||||
|
||||
// For special cases outside of where the auto-import strategy can have an impact
|
||||
// (like functional components as one of the examples),
|
||||
// you can manually specify Quasar components/directives to be available everywhere:
|
||||
//
|
||||
// components: [],
|
||||
// directives: [],
|
||||
|
||||
// Quasar plugins
|
||||
plugins: [
|
||||
"Notify",
|
||||
"Loading"
|
||||
]
|
||||
},
|
||||
|
||||
// animations: 'all', // --- includes all animations
|
||||
// https://v2.quasar.dev/options/animations
|
||||
animations: "all",
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli/developing-ssr/configuring-ssr
|
||||
ssr: {
|
||||
pwa: false,
|
||||
|
||||
// manualStoreHydration: true,
|
||||
// manualPostHydrationTrigger: true,
|
||||
|
||||
prodPort: 3000, // The default port that the production server should use
|
||||
// (gets superseded if process.env.PORT is specified at runtime)
|
||||
|
||||
maxAge: 1000 * 60 * 60 * 24 * 30,
|
||||
// Tell browser when a file from the server should expire from cache (in ms)
|
||||
|
||||
chainWebpackWebserver (/* chain */) {
|
||||
//
|
||||
},
|
||||
|
||||
middlewares: [
|
||||
ctx.prod ? "compression" : "",
|
||||
"render" // keep this as last one
|
||||
]
|
||||
},
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli/developing-pwa/configuring-pwa
|
||||
pwa: {
|
||||
workboxPluginMode: "GenerateSW", // 'GenerateSW' or 'InjectManifest'
|
||||
workboxOptions: {}, // only for GenerateSW
|
||||
|
||||
// for the custom service worker ONLY (/src-pwa/custom-service-worker.[js|ts])
|
||||
// if using workbox in InjectManifest mode
|
||||
chainWebpackCustomSW (/* chain */) {
|
||||
//
|
||||
},
|
||||
|
||||
manifest: {
|
||||
name: "Vircadia Domain Dashboard",
|
||||
short_name: "Vircadia Domain Dashboard",
|
||||
description: "The Domain dashboard for Vircadia virtual worlds.",
|
||||
display: "standalone",
|
||||
orientation: "portrait",
|
||||
background_color: "#ffffff",
|
||||
theme_color: "#027be3",
|
||||
icons: [
|
||||
{
|
||||
src: "icons/icon-128x128.png",
|
||||
sizes: "128x128",
|
||||
type: "image/png"
|
||||
},
|
||||
{
|
||||
src: "icons/icon-192x192.png",
|
||||
sizes: "192x192",
|
||||
type: "image/png"
|
||||
},
|
||||
{
|
||||
src: "icons/icon-256x256.png",
|
||||
sizes: "256x256",
|
||||
type: "image/png"
|
||||
},
|
||||
{
|
||||
src: "icons/icon-384x384.png",
|
||||
sizes: "384x384",
|
||||
type: "image/png"
|
||||
},
|
||||
{
|
||||
src: "icons/icon-512x512.png",
|
||||
sizes: "512x512",
|
||||
type: "image/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli/developing-cordova-apps/configuring-cordova
|
||||
cordova: {
|
||||
// noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing
|
||||
},
|
||||
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli/developing-capacitor-apps/configuring-capacitor
|
||||
capacitor: {
|
||||
hideSplashscreen: true
|
||||
},
|
||||
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli/developing-electron-apps/configuring-electron
|
||||
electron: {
|
||||
bundler: "packager", // 'packager' or 'builder'
|
||||
|
||||
packager: {
|
||||
// https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
|
||||
|
||||
// OS X / Mac App Store
|
||||
// appBundleId: '',
|
||||
// appCategoryType: '',
|
||||
// osxSign: '',
|
||||
// protocol: 'myapp://path',
|
||||
|
||||
// Windows only
|
||||
// win32metadata: { ... }
|
||||
},
|
||||
|
||||
builder: {
|
||||
// https://www.electron.build/configuration/configuration
|
||||
|
||||
appId: "vircadia-domain-dashboard"
|
||||
},
|
||||
|
||||
// "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain
|
||||
chainWebpack (/* chain */) {
|
||||
// do something with the Electron main process Webpack cfg
|
||||
// extendWebpackMain also available besides this chainWebpackMain
|
||||
},
|
||||
|
||||
// "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain
|
||||
chainWebpackPreload (/* chain */) {
|
||||
// do something with the Electron main process Webpack cfg
|
||||
// extendWebpackPreload also available besides this chainWebpackPreload
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
20
domain-server/resources/web/web-new/src/App.vue
Normal file
|
@ -0,0 +1,20 @@
|
|||
<!--
|
||||
// App.vue
|
||||
//
|
||||
// Created by Kalila L. on Sep. 4th, 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
-->
|
||||
|
||||
<template>
|
||||
<router-view />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "App"
|
||||
});
|
||||
</script>
|
BIN
domain-server/resources/web/web-new/src/assets/hq1.jpg
Normal file
After Width: | Height: | Size: 1.3 MiB |
BIN
domain-server/resources/web/web-new/src/assets/hub_world.zip
Normal file
After Width: | Height: | Size: 199 KiB |
0
domain-server/resources/web/web-new/src/boot/.gitkeep
Normal file
56
domain-server/resources/web/web-new/src/boot/axios.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
// axios.ts
|
||||
//
|
||||
// Created by Kalila L. on Sep. 4th, 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
import { boot } from "quasar/wrappers";
|
||||
import axios, { AxiosInstance } from "axios";
|
||||
import Log from "../modules/utilities/log";
|
||||
|
||||
declare module "@vue/runtime-core" {
|
||||
interface ComponentCustomProperties {
|
||||
$axios: AxiosInstance;
|
||||
}
|
||||
}
|
||||
|
||||
Log.info(Log.types.OTHER, "Bootstrapping Axios.");
|
||||
|
||||
// TODO: This needs to be centralized and not hardcoded.
|
||||
const METAVERSE_URL = "https://metaverse.vircadia.com/live";
|
||||
axios.interceptors.request.use((config) => {
|
||||
// This is a necessary header to be passed to the Metaverse server in order for
|
||||
// it to fail with an HTTP error code instead of succeeding and returning
|
||||
// the error in JSON only.
|
||||
if (config.url?.includes(METAVERSE_URL)) {
|
||||
config.headers["x-vircadia-error-handle"] = "badrequest";
|
||||
}
|
||||
console.info("config", config);
|
||||
return config;
|
||||
}, (error) => {
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
// Be careful when using SSR for cross-request state pollution
|
||||
// due to creating a Singleton instance here;
|
||||
// If any client changes this (global) instance, it might be a
|
||||
// good idea to move this instance creation inside of the
|
||||
// "export default () => {}" function below (which runs individually
|
||||
// for each client)
|
||||
const api = axios.create({ baseURL: "https://api.example.com" });
|
||||
|
||||
export default boot(({ app }) => {
|
||||
// for use inside Vue files (Options API) through this.$axios and this.$api
|
||||
|
||||
app.config.globalProperties.$axios = axios;
|
||||
// ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
|
||||
// so you won't necessarily have to import axios in each vue file
|
||||
|
||||
app.config.globalProperties.$api = api;
|
||||
// ^ ^ ^ this will allow you to use this.$api (for Vue Options API form)
|
||||
// so you can easily perform requests against your app's API
|
||||
});
|
||||
|
||||
export { api };
|
|
@ -0,0 +1,128 @@
|
|||
<!--
|
||||
// MetaverseLogin.vue
|
||||
//
|
||||
// Created by Kalila L. on May 18th, 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
-->
|
||||
|
||||
<template>
|
||||
<q-form
|
||||
@submit="onSubmit"
|
||||
@reset="onReset"
|
||||
class="q-gutter-md"
|
||||
:autocomplete="AUTOCOMPLETE"
|
||||
>
|
||||
<q-input
|
||||
v-model="username"
|
||||
filled
|
||||
dark
|
||||
label="Username"
|
||||
hint="Enter your username."
|
||||
lazy-rules
|
||||
:rules="[ val => val && val.length > 0 || 'Please enter a username.']"
|
||||
/>
|
||||
|
||||
<q-input
|
||||
v-model="password"
|
||||
filled
|
||||
dark
|
||||
label="Password"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
hint="Enter your password."
|
||||
lazy-rules
|
||||
:rules="[ val => val && val.length > 0 || 'Please enter a password.']"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<q-icon
|
||||
:name="showPassword ? 'visibility' : 'visibility_off'"
|
||||
class="cursor-pointer"
|
||||
@click="showPassword = !showPassword"
|
||||
/>
|
||||
</template>
|
||||
</q-input>
|
||||
|
||||
<div align="right">
|
||||
<q-btn label="Reset" type="reset" color="primary" flat class="q-mr-sm" />
|
||||
<q-btn label="Login" type="submit" color="primary"/>
|
||||
</div>
|
||||
</q-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// FIXME: Needs to be done correctly. Also universally? Maybe window.axios?
|
||||
const axios = require("axios");
|
||||
|
||||
import Log from "../../../modules/utilities/log";
|
||||
|
||||
export default {
|
||||
name: "MetaverseLogin",
|
||||
|
||||
emits: ["loginResult"],
|
||||
|
||||
data: () => ({
|
||||
username: "",
|
||||
password: "",
|
||||
showPassword: false,
|
||||
// TODO: Needs to be stored somewhere central.
|
||||
DEFAULT_METAVERSE_URL: "https://metaverse.vircadia.com/live",
|
||||
AUTOCOMPLETE: false
|
||||
}),
|
||||
|
||||
methods: {
|
||||
async onSubmit () {
|
||||
const metaverseUrl = await this.retrieveMetaverseUrl();
|
||||
const result = await this.attemptLogin(metaverseUrl, this.username, this.password);
|
||||
|
||||
this.$emit("loginResult", { "success": result.success, "metaverse": metaverseUrl, "data": result.response });
|
||||
},
|
||||
|
||||
// TODO: This needs to be addressed in a more modular fashion to reuse and save state across multiple components.
|
||||
async retrieveMetaverseUrl () {
|
||||
return new Promise((resolve) => {
|
||||
axios.get("/api/metaverse_info")
|
||||
.then((response) => {
|
||||
Log.info(Log.types.METAVERSE, `Retrieved Metaverse URL ${response.data.metaverse_url}.`);
|
||||
resolve(response.data.metaverse_url);
|
||||
}, (error) => {
|
||||
Log.error(Log.types.METAVERSE, `Failed to retrieve Metaverse URL, using default URL ${this.DEFAULT_METAVERSE_URL} instead. Error: ${error}`);
|
||||
resolve(this.DEFAULT_METAVERSE_URL);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
async attemptLogin (metaverse, username, password) {
|
||||
Log.info(Log.types.METAVERSE, `Attempting to login as ${username}.`);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
axios.post(`${metaverse}/oauth/token`, {
|
||||
grant_type: "password",
|
||||
scope: "owner", // as opposed to 'domain', we're asking for a user token
|
||||
username: username,
|
||||
password: password
|
||||
})
|
||||
.then((response) => {
|
||||
Log.info(Log.types.METAVERSE, `Successfully got key and details for ${username}.`);
|
||||
resolve({ "success": true, "response": response.data });
|
||||
}, (error) => {
|
||||
Log.error(Log.types.METAVERSE, `Failed to get key and details for ${username}.`);
|
||||
if (error.response && error.response.data) {
|
||||
resolve({ "success": false, "response": error.response.data });
|
||||
} else if (error) {
|
||||
resolve({ "success": false, "response": error });
|
||||
} else {
|
||||
resolve({ "success": false, "response": "Unknown reason." });
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
onReset () {
|
||||
this.username = "";
|
||||
this.password = "";
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,131 @@
|
|||
<!--
|
||||
// ConnectMetaverse.vue
|
||||
//
|
||||
// Created by Kalila L. on Sep. 5th, 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
-->
|
||||
|
||||
<template>
|
||||
<q-card-section>
|
||||
<div class="row no-wrap items-center">
|
||||
<div class="col text-h4 ellipsis">
|
||||
Metaverse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</q-card-section>
|
||||
|
||||
<q-separator />
|
||||
|
||||
<q-card-section>
|
||||
<MetaverseLogin @loginResult="onLoginAttempt"></MetaverseLogin>
|
||||
</q-card-section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// FIXME: Needs to be done correctly. Also universally? Maybe window.axios?
|
||||
const axios = require("axios");
|
||||
|
||||
// Components
|
||||
import MetaverseLogin from "../components/login/MetaverseLogin.vue";
|
||||
// Modules
|
||||
import Log from "../../modules/utilities/log";
|
||||
|
||||
export default {
|
||||
name: "ConnectMetaverse",
|
||||
|
||||
components: {
|
||||
MetaverseLogin
|
||||
},
|
||||
|
||||
emits: ["connectionResult"],
|
||||
|
||||
data: () => ({
|
||||
}),
|
||||
|
||||
methods: {
|
||||
onLoginAttempt (result) {
|
||||
if (result.success === true) {
|
||||
Log.info(Log.types.METAVERSE, `Successfully logged in as ${result.data.account_name} for Metaverse linking.`);
|
||||
// Get a token for our server from the Metaverse.
|
||||
axios.post(`${result.metaverse}/api/v1/token/new`, {}, {
|
||||
params: {
|
||||
// "asAdmin": store.account.useAsAdmin,
|
||||
"scope": "domain"
|
||||
},
|
||||
headers: {
|
||||
"Authorization": `Bearer ${result.data.access_token}`
|
||||
}
|
||||
})
|
||||
.catch((result) => {
|
||||
Log.error(Log.types.METAVERSE, "Failed to link server with Metaverse.");
|
||||
|
||||
this.$q.notify({
|
||||
type: "negative",
|
||||
textColor: "white",
|
||||
icon: "warning",
|
||||
message: `Metaverse link attempt failed. ${result}`
|
||||
});
|
||||
})
|
||||
.then(async (response) => {
|
||||
Log.info(Log.types.METAVERSE, "Successfully got Domain token for Metaverse linking.");
|
||||
|
||||
const settingsToCommit = {
|
||||
"metaverse": {
|
||||
"access_token": response.data.data.token
|
||||
}
|
||||
};
|
||||
|
||||
const committed = await this.commitSettings(settingsToCommit);
|
||||
|
||||
if (committed === true) {
|
||||
Log.info(Log.types.METAVERSE, "Successfully committed Domain server access token for the Metaverse.");
|
||||
this.$q.notify({
|
||||
type: "positive",
|
||||
textColor: "white",
|
||||
icon: "cloud_done",
|
||||
message: "Successfully linked your server to the Metaverse."
|
||||
});
|
||||
|
||||
this.$emit("connectionResult", { "success": true });
|
||||
} else {
|
||||
Log.error(Log.types.METAVERSE, "Failed to link server with Metaverse: Could not commit token to settings.");
|
||||
this.$q.notify({
|
||||
type: "negative",
|
||||
textColor: "white",
|
||||
icon: "warning",
|
||||
message: "Metaverse link attempt failed because the settings were unable to be saved."
|
||||
});
|
||||
|
||||
this.$emit("connectionResult", { "success": false });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$q.notify({
|
||||
type: "negative",
|
||||
textColor: "white",
|
||||
icon: "warning",
|
||||
message: `Login attempt failed: ${result.data.error}`
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: This needs to go somewhere universal.
|
||||
commitSettings (settingsToCommit) {
|
||||
// TODO: This and all other URL endpoints should be in centralized (in their respective module) constants files.
|
||||
return axios.post("/settings.json", JSON.stringify(settingsToCommit))
|
||||
.then(() => {
|
||||
Log.info(Log.types.DOMAIN, "Successfully committed settings.");
|
||||
return true;
|
||||
})
|
||||
.catch((response) => {
|
||||
Log.error(Log.types.DOMAIN, `Failed to commit settings to Domain: ${response}`);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
1
domain-server/resources/web/web-new/src/css/app.scss
Normal file
|
@ -0,0 +1 @@
|
|||
// app global css in SCSS form
|
|
@ -0,0 +1,24 @@
|
|||
// Quasar SCSS (& Sass) Variables
|
||||
// --------------------------------------------------
|
||||
// To customize the look and feel of this app, you can override
|
||||
// the Sass/SCSS variables found in Quasar's source Sass/SCSS files.
|
||||
|
||||
// Check documentation for full list of Quasar variables
|
||||
|
||||
// Your own variables (that are declared here) and Quasar's own
|
||||
// ones will be available out of the box in your .vue/.scss/.sass files
|
||||
|
||||
// It's highly recommended to change the default colors
|
||||
// to match your app's branding.
|
||||
// Tip: Use the "Theme Builder" on Quasar's documentation website.
|
||||
|
||||
$primary : #1976D2;
|
||||
$secondary : #26A69A;
|
||||
$accent : #9C27B0;
|
||||
|
||||
$dark : #1D1D1D;
|
||||
|
||||
$positive : #21BA45;
|
||||
$negative : #C10015;
|
||||
$info : #31CCEC;
|
||||
$warning : #F2C037;
|
7
domain-server/resources/web/web-new/src/env.d.ts
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
declare namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
NODE_ENV: string;
|
||||
VUE_ROUTER_MODE: "hash" | "history" | "abstract" | undefined;
|
||||
VUE_ROUTER_BASE: string | undefined;
|
||||
}
|
||||
}
|
32
domain-server/resources/web/web-new/src/index.template.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!--
|
||||
// index.template.html
|
||||
//
|
||||
// Created by Kalila L. on Sep. 4th, 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><%= productName %></title>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="description" content="<%= productDescription %>">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="msapplication-tap-highlight" content="no">
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>">
|
||||
|
||||
<link rel="icon" type="image/png" sizes="128x128" href="icons/favicon-128x128.png">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="icons/favicon-96x96.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="icons/favicon-16x16.png">
|
||||
<link rel="icon" type="image/ico" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<!-- DO NOT touch the following DIV -->
|
||||
<div id="q-app"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,85 @@
|
|||
<!--
|
||||
// FirstTimeWizard.vue
|
||||
//
|
||||
// Created by Kalila L. on Sep. 4th, 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
-->
|
||||
|
||||
<template>
|
||||
<q-layout id="vantaBG" view="hHh lpR fFf">
|
||||
<q-page-container>
|
||||
<div id="firstTimeWizardContainer">
|
||||
<router-view />
|
||||
</div>
|
||||
</q-page-container>
|
||||
</q-layout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
import * as THREE from "three";
|
||||
|
||||
export default defineComponent({
|
||||
name: "FirstTimeWizard",
|
||||
data () {
|
||||
return {
|
||||
vantaBG: null,
|
||||
vantaRings: null,
|
||||
refreshVantaTimeout: null,
|
||||
DELAY_REFRESH_VANTA: 500
|
||||
};
|
||||
},
|
||||
async mounted () {
|
||||
window.THREE = THREE;
|
||||
this.vantaRings = (await import("vanta/dist/vanta.rings.min")).default;
|
||||
|
||||
this.initVanta();
|
||||
|
||||
visualViewport.addEventListener("resize", this.onResize);
|
||||
},
|
||||
methods: {
|
||||
onResize () {
|
||||
if (this.refreshVantaTimeout) {
|
||||
clearTimeout(this.refreshVantaTimeout);
|
||||
}
|
||||
|
||||
this.refreshVantaTimeout = setTimeout(() => {
|
||||
this.initVanta();
|
||||
this.refreshVantaTimeout = null;
|
||||
}, this.DELAY_REFRESH_VANTA);
|
||||
},
|
||||
initVanta () {
|
||||
if (this.vantaBG) {
|
||||
this.vantaBG.destroy();
|
||||
}
|
||||
|
||||
this.vantaBG = this.vantaRings({
|
||||
el: "#vantaBG",
|
||||
mouseControls: false,
|
||||
touchControls: false,
|
||||
gyroControls: false,
|
||||
minHeight: 200.00,
|
||||
minWidth: 200.00,
|
||||
scale: 1.00,
|
||||
scaleMobile: 1.00,
|
||||
color: 0x000000
|
||||
// waveHeight: 20,
|
||||
// shininess: 50,
|
||||
// waveSpeed: 1.5,
|
||||
// zoom: 0.75,
|
||||
// backgroundColor: 0x4e97e1,
|
||||
// backgroundAlpha: 0.40
|
||||
});
|
||||
}
|
||||
},
|
||||
beforeUnmount () {
|
||||
if (this.vantaBG) {
|
||||
this.vantaBG.destroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
// log.js
|
||||
//
|
||||
// Created by Kalila L. on May 10th, 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
|
||||
const Log = (function () {
|
||||
enum types {
|
||||
OTHER = "[OTHER]",
|
||||
DOMAIN = "[DOMAIN]",
|
||||
METAVERSE = "[METAVERSE]"
|
||||
}
|
||||
|
||||
enum levels {
|
||||
ERROR = "[ERROR]",
|
||||
DEBUG = "[DEBUG]",
|
||||
WARN = "[WARN]",
|
||||
INFO = "[INFO]"
|
||||
}
|
||||
|
||||
function print (pType: types, pLevel: levels, pMsg: string): void {
|
||||
console.info(pType, pLevel, pMsg);
|
||||
}
|
||||
|
||||
// Print out message if debugging
|
||||
function debug (pType: types, pMsg: string) {
|
||||
print(pType, levels.DEBUG, pMsg);
|
||||
}
|
||||
|
||||
function error (pType: types, pMsg: string) {
|
||||
print(pType, levels.ERROR, pMsg);
|
||||
}
|
||||
|
||||
function warn (pType: types, pMsg: string) {
|
||||
print(pType, levels.WARN, pMsg);
|
||||
}
|
||||
|
||||
function info (pType: types, pMsg: string) {
|
||||
print(pType, levels.INFO, pMsg);
|
||||
}
|
||||
|
||||
return {
|
||||
// Tables
|
||||
types,
|
||||
levels,
|
||||
// Functions
|
||||
print,
|
||||
debug,
|
||||
error,
|
||||
warn,
|
||||
info
|
||||
};
|
||||
}());
|
||||
|
||||
export default Log;
|
41
domain-server/resources/web/web-new/src/pages/Error404.vue
Normal file
|
@ -0,0 +1,41 @@
|
|||
<!--
|
||||
// Index.vue
|
||||
//
|
||||
// Created by Kalila L. on Sep. 4th, 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="fullscreen bg-blue text-white text-center q-pa-md flex flex-center">
|
||||
<div>
|
||||
<div style="font-size: 30vh">
|
||||
404
|
||||
</div>
|
||||
|
||||
<div class="text-h2" style="opacity:.4">
|
||||
Oops. Nothing here...
|
||||
</div>
|
||||
|
||||
<q-btn
|
||||
class="q-mt-xl"
|
||||
color="white"
|
||||
text-color="blue"
|
||||
unelevated
|
||||
to="/"
|
||||
label="Go Home"
|
||||
no-caps
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Error404"
|
||||
});
|
||||
</script>
|
21
domain-server/resources/web/web-new/src/pages/Index.vue
Normal file
|
@ -0,0 +1,21 @@
|
|||
<!--
|
||||
// Index.vue
|
||||
//
|
||||
// Created by Kalila L. on Sep. 4th, 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
-->
|
||||
|
||||
<template>
|
||||
<h1>Test</h1>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Index"
|
||||
});
|
||||
</script>
|
46
domain-server/resources/web/web-new/src/router/index.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
// index.ts
|
||||
//
|
||||
// Created by Kalila L. on Sep. 4th, 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
import { route } from "quasar/wrappers";
|
||||
import {
|
||||
createMemoryHistory,
|
||||
createRouter,
|
||||
createWebHashHistory,
|
||||
createWebHistory
|
||||
} from "vue-router";
|
||||
import { StateInterface } from "../store";
|
||||
import routes from "./routes";
|
||||
|
||||
/*
|
||||
* If not building with SSR mode, you can
|
||||
* directly export the Router instantiation;
|
||||
*
|
||||
* The function below can be async too; either use
|
||||
* async/await or return a Promise which resolves
|
||||
* with the Router instance.
|
||||
*/
|
||||
|
||||
export default route<StateInterface>(function (/* { store, ssrContext } */) {
|
||||
const createHistory = process.env.SERVER
|
||||
? createMemoryHistory
|
||||
: (process.env.VUE_ROUTER_MODE === "history" ? createWebHistory : createWebHashHistory);
|
||||
|
||||
const Router = createRouter({
|
||||
scrollBehavior: () => ({ left: 0, top: 0 }),
|
||||
routes,
|
||||
|
||||
// Leave this as is and make changes in quasar.conf.js instead!
|
||||
// quasar.conf.js -> build -> vueRouterMode
|
||||
// quasar.conf.js -> build -> publicPath
|
||||
history: createHistory(
|
||||
process.env.MODE === "ssr" ? void 0 : process.env.VUE_ROUTER_BASE
|
||||
)
|
||||
});
|
||||
|
||||
return Router;
|
||||
});
|
31
domain-server/resources/web/web-new/src/router/routes.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
// routes.ts
|
||||
//
|
||||
// Created by Kalila L. on Sep. 4th, 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: "/",
|
||||
component: () => import("pages/Index.vue"),
|
||||
children: [{ path: "", component: () => import("pages/Index.vue") }]
|
||||
},
|
||||
{
|
||||
path: "/wizard",
|
||||
component: () => import("layouts/FirstTimeWizard.vue"),
|
||||
children: [{ path: "", component: () => import("pages/FirstTimeWizard/Index.vue") }]
|
||||
},
|
||||
|
||||
// Always leave this as last one,
|
||||
// but you can also remove it
|
||||
{
|
||||
path: "/:catchAll(.*)*",
|
||||
component: () => import("pages/Error404.vue")
|
||||
}
|
||||
];
|
||||
|
||||
export default routes;
|
6
domain-server/resources/web/web-new/src/shims-vue.d.ts
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Mocks all files ending in `.vue` showing them as plain Vue instances
|
||||
declare module "*.vue" {
|
||||
import { ComponentOptions } from "vue";
|
||||
const component: ComponentOptions;
|
||||
export default component;
|
||||
}
|
62
domain-server/resources/web/web-new/src/store/index.ts
Normal file
|
@ -0,0 +1,62 @@
|
|||
// index.ts
|
||||
//
|
||||
// Created by Kalila L. on Sep. 4th, 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
import { store } from "quasar/wrappers";
|
||||
import { InjectionKey } from "vue";
|
||||
import {
|
||||
createStore,
|
||||
Store as VuexStore,
|
||||
useStore as vuexUseStore
|
||||
} from "vuex";
|
||||
|
||||
// import example from './module-example'
|
||||
import { MainState } from "./modules/state";
|
||||
|
||||
/*
|
||||
* If not building with SSR mode, you can
|
||||
* directly export the Store instantiation;
|
||||
*
|
||||
* The function below can be async too; either use
|
||||
* async/await or return a Promise which resolves
|
||||
* with the Store instance.
|
||||
*/
|
||||
|
||||
export interface StateInterface {
|
||||
// Define your own store structure, using submodules if needed
|
||||
// example: ExampleStateInterface;
|
||||
// Declared as unknown to avoid linting issue. Best to strongly type as per the line above.
|
||||
MainState: MainState
|
||||
}
|
||||
|
||||
// provide typings for `this.$store`
|
||||
declare module "@vue/runtime-core" {
|
||||
interface ComponentCustomProperties {
|
||||
$store: VuexStore<StateInterface>
|
||||
}
|
||||
}
|
||||
|
||||
// provide typings for `useStore` helper
|
||||
export const storeKey: InjectionKey<VuexStore<StateInterface>> = Symbol("vuex-key");
|
||||
|
||||
export default store(function (/* { ssrContext } */) {
|
||||
const Store = createStore<StateInterface>({
|
||||
modules: {
|
||||
// example
|
||||
},
|
||||
|
||||
// enable strict mode (adds overhead!)
|
||||
// for dev mode and --debug builds only
|
||||
strict: !!process.env.DEBUGGING
|
||||
});
|
||||
|
||||
return Store;
|
||||
});
|
||||
|
||||
export function useStore () {
|
||||
return vuexUseStore(storeKey);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import { ActionTree } from "vuex";
|
||||
import { StateInterface } from "../index";
|
||||
import { MainState } from "./state";
|
||||
|
||||
const actions: ActionTree<MainState, StateInterface> = {
|
||||
someAction (/* context */) {
|
||||
// your code
|
||||
}
|
||||
};
|
||||
|
||||
export default actions;
|
|
@ -0,0 +1,11 @@
|
|||
import { GetterTree } from "vuex";
|
||||
import { StateInterface } from "../index";
|
||||
import { MainState } from "./state";
|
||||
|
||||
const getters: GetterTree<MainState, StateInterface> = {
|
||||
someAction (/* context */) {
|
||||
// your code
|
||||
}
|
||||
};
|
||||
|
||||
export default getters;
|
|
@ -0,0 +1,16 @@
|
|||
import { Module } from "vuex";
|
||||
import { StateInterface } from "../index";
|
||||
import state, { MainState } from "./state";
|
||||
import actions from "./actions";
|
||||
import getters from "./getters";
|
||||
import mutations from "./mutations";
|
||||
|
||||
const exampleModule: Module<MainState, StateInterface> = {
|
||||
namespaced: true,
|
||||
actions,
|
||||
getters,
|
||||
mutations,
|
||||
state
|
||||
};
|
||||
|
||||
export default exampleModule;
|
|
@ -0,0 +1,10 @@
|
|||
import { MutationTree } from "vuex";
|
||||
import { MainState } from "./state";
|
||||
|
||||
const mutation: MutationTree<MainState> = {
|
||||
someMutation (/* state: ExampleStateInterface */) {
|
||||
// your code
|
||||
}
|
||||
};
|
||||
|
||||
export default mutation;
|
|
@ -0,0 +1,11 @@
|
|||
export interface MainState {
|
||||
prop: boolean;
|
||||
}
|
||||
|
||||
function state (): MainState {
|
||||
return {
|
||||
prop: false
|
||||
};
|
||||
}
|
||||
|
||||
export default state;
|
10
domain-server/resources/web/web-new/src/store/store-flag.d.ts
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
/* eslint-disable */
|
||||
// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
|
||||
// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
|
||||
import "quasar/dist/types/feature-flag";
|
||||
|
||||
declare module "quasar/dist/types/feature-flag" {
|
||||
interface QuasarFeatureFlags {
|
||||
store: true;
|
||||
}
|
||||
}
|
6
domain-server/resources/web/web-new/tsconfig.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"extends": "@quasar/app/tsconfig-preset",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./web-new"
|
||||
}
|
||||
}
|
|
@ -86,7 +86,16 @@ bool DomainServer::_getTempName { false };
|
|||
QString DomainServer::_userConfigFilename;
|
||||
int DomainServer::_parentPID { -1 };
|
||||
|
||||
/// @brief The Domain server can proxy requests to the Metaverse server, this function handles those forwarding requests.
|
||||
/// @param connection The HTTP connection object.
|
||||
/// @param requestUrl The full URL of the request. e.g. https://google.com/api/v1/test
|
||||
/// @param metaversePath The path on the Metaverse server to route to.
|
||||
/// @param requestSubobjectKey (Optional) The parent object key that any data will be inserted into for the forwarded request.
|
||||
/// @param requiredData (Optional) This data is required to be present for the request.
|
||||
/// @param optionalData (Optional) If provided, this optional data will be forwarded with the request.
|
||||
/// @param requireAccessToken Require a valid access token to be sent with this request.
|
||||
bool DomainServer::forwardMetaverseAPIRequest(HTTPConnection* connection,
|
||||
const QUrl& requestUrl,
|
||||
const QString& metaversePath,
|
||||
const QString& requestSubobjectKey,
|
||||
std::initializer_list<QString> requiredData,
|
||||
|
@ -101,23 +110,43 @@ bool DomainServer::forwardMetaverseAPIRequest(HTTPConnection* connection,
|
|||
|
||||
QJsonObject subobject;
|
||||
|
||||
auto params = connection->parseUrlEncodedForm();
|
||||
if (requestUrl.hasQuery()) {
|
||||
QUrlQuery query(requestUrl);
|
||||
|
||||
for (auto& key : requiredData) {
|
||||
auto it = params.find(key);
|
||||
if (it == params.end()) {
|
||||
auto error = "Bad request, expected param '" + key + "'";
|
||||
connection->respond(HTTPConnection::StatusCode400, error.toLatin1());
|
||||
return true;
|
||||
for (auto& key : requiredData) {
|
||||
if (query.hasQueryItem(key)) {
|
||||
subobject.insert(key, query.queryItemValue(key));
|
||||
} else {
|
||||
auto error = "Domain Server: Bad request, expected param '" + key + "'";
|
||||
connection->respond(HTTPConnection::StatusCode400, error.toLatin1());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
subobject.insert(key, it.value());
|
||||
}
|
||||
|
||||
for (auto& key : optionalData) {
|
||||
auto it = params.find(key);
|
||||
if (it != params.end()) {
|
||||
for (auto& key : optionalData) {
|
||||
if (query.hasQueryItem(key)) {
|
||||
subobject.insert(key, query.queryItemValue(key));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto params = connection->parseUrlEncodedForm();
|
||||
|
||||
for (auto& key : requiredData) {
|
||||
auto it = params.find(key);
|
||||
if (it == params.end()) {
|
||||
auto error = "Domain Server: Bad request, expected param '" + key + "'";
|
||||
connection->respond(HTTPConnection::StatusCode400, error.toLatin1());
|
||||
return true;
|
||||
}
|
||||
subobject.insert(key, it.value());
|
||||
}
|
||||
|
||||
for (auto& key : optionalData) {
|
||||
auto it = params.find(key);
|
||||
if (it != params.end()) {
|
||||
subobject.insert(key, it.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject root;
|
||||
|
@ -443,7 +472,7 @@ DomainServer::~DomainServer() {
|
|||
_contentManager->aboutToFinish();
|
||||
_contentManager->terminate();
|
||||
}
|
||||
|
||||
|
||||
if (_httpMetadataExporterManager) {
|
||||
_httpMetadataExporterManager->close();
|
||||
delete _httpMetadataExporterManager;
|
||||
|
@ -2199,23 +2228,25 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
|
||||
// Check if we should redirect/prevent access to the wizard
|
||||
if (connection->requestOperation() == QNetworkAccessManager::GetOperation) {
|
||||
const QString URI_WIZARD = "/wizard/";
|
||||
const QString URI_WIZARD_PATH = "/web-new/dist/spa/index.html";
|
||||
const QString URI_WIZARD_FRAG = "wizard";
|
||||
const QString WIZARD_COMPLETED_ONCE_KEY_PATH = "wizard.completed_once";
|
||||
QVariant wizardCompletedOnce = _settingsManager.valueForKeyPath(WIZARD_COMPLETED_ONCE_KEY_PATH);
|
||||
const bool completedOnce = wizardCompletedOnce.isValid() && wizardCompletedOnce.toBool();
|
||||
|
||||
if (url.path() != URI_WIZARD && url.path().endsWith('/') && !completedOnce) {
|
||||
if (url.path() != URI_WIZARD_PATH && url.path().endsWith('/') && !completedOnce) {
|
||||
// First visit, redirect to the wizard
|
||||
QUrl redirectedURL = url;
|
||||
redirectedURL.setPath(URI_WIZARD);
|
||||
redirectedURL.setPath(URI_WIZARD_PATH);
|
||||
redirectedURL.setFragment(URI_WIZARD_FRAG);
|
||||
|
||||
Headers redirectHeaders;
|
||||
redirectHeaders.insert("Location", redirectedURL.toEncoded());
|
||||
redirectHeaders.insert("Location", redirectedURL.toEncoded(QUrl::None));
|
||||
|
||||
connection->respond(HTTPConnection::StatusCode302,
|
||||
QByteArray(), HTTPConnection::DefaultContentType, redirectHeaders);
|
||||
return true;
|
||||
} else if (url.path() == URI_WIZARD && completedOnce) {
|
||||
} else if (url.path() == URI_WIZARD_PATH && completedOnce) {
|
||||
// Wizard already completed, return 404
|
||||
connection->respond(HTTPConnection::StatusCode404, "Resource not found.");
|
||||
return true;
|
||||
|
@ -2370,12 +2401,12 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
|
||||
return true;
|
||||
} else if (url.path() == URI_API_DOMAINS) {
|
||||
return forwardMetaverseAPIRequest(connection, "/api/v1/domains", "");
|
||||
return forwardMetaverseAPIRequest(connection, url, "/api/v1/domains");
|
||||
} else if (url.path().startsWith(URI_API_DOMAINS_ID)) {
|
||||
auto id = url.path().mid(URI_API_DOMAINS_ID.length());
|
||||
return forwardMetaverseAPIRequest(connection, "/api/v1/domains/" + id, "", {}, {}, false);
|
||||
return forwardMetaverseAPIRequest(connection, url, "/api/v1/domains/" + id, "", {}, {}, false);
|
||||
} else if (url.path() == URI_API_PLACES) {
|
||||
return forwardMetaverseAPIRequest(connection, "/api/v1/user/places", "");
|
||||
return forwardMetaverseAPIRequest(connection, url, "/api/v1/user/places");
|
||||
} else {
|
||||
// check if this is for json stats for a node
|
||||
const QString NODE_JSON_REGEX_STRING = QString("\\%1\\/(%2).json\\/?$").arg(URI_NODES).arg(UUID_REGEX_STRING);
|
||||
|
@ -2512,7 +2543,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
}
|
||||
|
||||
} else if (url.path() == URI_API_DOMAINS) {
|
||||
return forwardMetaverseAPIRequest(connection, "/api/v1/domains", "domain", { "label" });
|
||||
return forwardMetaverseAPIRequest(connection, url, "/api/v1/domains", "domain", { "label" });
|
||||
|
||||
} else if (url.path().startsWith(URI_API_BACKUPS_RECOVER)) {
|
||||
auto id = url.path().mid(QString(URI_API_BACKUPS_RECOVER).length());
|
||||
|
@ -2539,7 +2570,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
return true;
|
||||
}
|
||||
auto domainID = domainSetting.toString();
|
||||
return forwardMetaverseAPIRequest(connection, "/api/v1/domains/" + domainID, "domain",
|
||||
return forwardMetaverseAPIRequest(connection, url, "/api/v1/domains/" + domainID, "domain",
|
||||
{ }, { "network_address", "network_port", "label" });
|
||||
} else if (url.path() == URI_API_PLACES) {
|
||||
auto accessTokenVariant = _settingsManager.valueForKeyPath(ACCESS_TOKEN_KEY_PATH);
|
||||
|
@ -3227,9 +3258,9 @@ void DomainServer::initializeExporter() {
|
|||
qCInfo(domain_server) << "Starting Prometheus exporter on port " << exporterPort;
|
||||
_httpExporterManager = new HTTPManager
|
||||
(
|
||||
QHostAddress::Any,
|
||||
(quint16)exporterPort,
|
||||
QString("%1/resources/prometheus_exporter/").arg(QCoreApplication::applicationDirPath()),
|
||||
QHostAddress::Any,
|
||||
(quint16)exporterPort,
|
||||
QString("%1/resources/prometheus_exporter/").arg(QCoreApplication::applicationDirPath()),
|
||||
&_exporter
|
||||
);
|
||||
}
|
||||
|
@ -3253,9 +3284,9 @@ void DomainServer::initializeMetadataExporter() {
|
|||
qCInfo(domain_server) << "Starting Metadata exporter on port" << metadataExporterPort;
|
||||
_httpMetadataExporterManager = new HTTPManager
|
||||
(
|
||||
QHostAddress::Any,
|
||||
(quint16)metadataExporterPort,
|
||||
QString("%1/resources/metadata_exporter/").arg(QCoreApplication::applicationDirPath()),
|
||||
QHostAddress::Any,
|
||||
(quint16)metadataExporterPort,
|
||||
QString("%1/resources/metadata_exporter/").arg(QCoreApplication::applicationDirPath()),
|
||||
_metadata
|
||||
);
|
||||
}
|
||||
|
@ -3877,7 +3908,7 @@ void DomainServer::screensharePresence(QString roomname, QUuid avatarID, int exp
|
|||
callbackParams.jsonCallbackMethod = "handleSuccessfulScreensharePresence";
|
||||
callbackParams.errorCallbackMethod = "handleFailedScreensharePresence";
|
||||
// Construct `callbackData`, which is data that will be available to the callback functions.
|
||||
// In this case, the "success" callback needs access to the "roomname" (the zone ID) and the
|
||||
// In this case, the "success" callback needs access to the "roomname" (the zone ID) and the
|
||||
// relevant avatar's UUID.
|
||||
QJsonObject callbackData;
|
||||
callbackData.insert("roomname", roomname);
|
||||
|
|
|
@ -241,8 +241,9 @@ private:
|
|||
bool processPendingContent(HTTPConnection* connection, QString itemName, QString filename, QByteArray dataChunk);
|
||||
|
||||
bool forwardMetaverseAPIRequest(HTTPConnection* connection,
|
||||
const QUrl& requestUrl,
|
||||
const QString& metaversePath,
|
||||
const QString& requestSubobject,
|
||||
const QString& requestSubobjectKey = "",
|
||||
std::initializer_list<QString> requiredData = { },
|
||||
std::initializer_list<QString> optionalData = { },
|
||||
bool requireAccessToken = true);
|
||||
|
@ -265,7 +266,7 @@ private:
|
|||
HTTPManager _httpManager;
|
||||
HTTPManager* _httpExporterManager { nullptr };
|
||||
HTTPManager* _httpMetadataExporterManager { nullptr };
|
||||
|
||||
|
||||
std::unique_ptr<HTTPSManager> _httpsManager;
|
||||
|
||||
QHash<QUuid, SharedAssignmentPointer> _allAssignments;
|
||||
|
|
|
@ -176,7 +176,7 @@ QList<FormData> HTTPConnection::parseFormData() const {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QByteArray start = "--" + boundary;
|
||||
QByteArray end = "\r\n--" + boundary + "--\r\n";
|
||||
|
||||
|
@ -394,6 +394,6 @@ void HTTPConnection::readContent() {
|
|||
if (_requestContent->bytesLeftToWrite() == 0) {
|
||||
_socket->disconnect(this, SLOT(readContent()));
|
||||
|
||||
_parentManager->handleHTTPRequest(this, _requestUrl.path());
|
||||
_parentManager->handleHTTPRequest(this, _requestUrl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ QString FileUtils::readFile(const QString& filename) {
|
|||
return result;
|
||||
}
|
||||
|
||||
QStringList FileUtils::readLines(const QString& filename, QString::SplitBehavior splitBehavior) {
|
||||
QStringList FileUtils::readLines(const QString& filename, Qt::SplitBehavior splitBehavior) {
|
||||
return readFile(filename).split(QRegularExpression("[\\r\\n]"), Qt::SkipEmptyParts);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
static bool isRelative(const QString& fileName);
|
||||
static QString standardPath(QString subfolder);
|
||||
static QString readFile(const QString& filename);
|
||||
static QStringList readLines(const QString& filename, QString::SplitBehavior splitBehavior = QString::KeepEmptyParts);
|
||||
static QStringList readLines(const QString& filename, Qt::SplitBehavior splitBehavior = Qt::KeepEmptyParts);
|
||||
static QString replaceDateTimeTokens(const QString& path);
|
||||
static QString computeDocumentPath(const QString& path);
|
||||
static bool canCreateFile(const QString& fullPath);
|
||||
|
|