mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 16:23:17 +02:00
initial separation of content settings and domain settings
This commit is contained in:
parent
6187731fdc
commit
6240181474
20 changed files with 2485 additions and 2237 deletions
|
@ -935,6 +935,7 @@
|
||||||
"name": "persistent_scripts",
|
"name": "persistent_scripts",
|
||||||
"type": "table",
|
"type": "table",
|
||||||
"label": "Persistent Scripts",
|
"label": "Persistent Scripts",
|
||||||
|
"content_setting": true,
|
||||||
"help": "Add the URLs for scripts that you would like to ensure are always running in your domain.",
|
"help": "Add the URLs for scripts that you would like to ensure are always running in your domain.",
|
||||||
"can_add_new_rows": true,
|
"can_add_new_rows": true,
|
||||||
"columns": [
|
"columns": [
|
||||||
|
@ -1105,6 +1106,7 @@
|
||||||
"label": "Zones",
|
"label": "Zones",
|
||||||
"help": "In this table you can define a set of zones in which you can specify various audio properties.",
|
"help": "In this table you can define a set of zones in which you can specify various audio properties.",
|
||||||
"numbered": false,
|
"numbered": false,
|
||||||
|
"content_setting": true,
|
||||||
"can_add_new_rows": true,
|
"can_add_new_rows": true,
|
||||||
"key": {
|
"key": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
|
@ -1155,6 +1157,7 @@
|
||||||
"type": "table",
|
"type": "table",
|
||||||
"label": "Attenuation Coefficients",
|
"label": "Attenuation Coefficients",
|
||||||
"help": "In this table you can set custom attenuation coefficients between audio zones",
|
"help": "In this table you can set custom attenuation coefficients between audio zones",
|
||||||
|
"content_setting": true,
|
||||||
"numbered": true,
|
"numbered": true,
|
||||||
"can_order": true,
|
"can_order": true,
|
||||||
"can_add_new_rows": true,
|
"can_add_new_rows": true,
|
||||||
|
@ -1185,6 +1188,7 @@
|
||||||
"label": "Reverb Settings",
|
"label": "Reverb Settings",
|
||||||
"help": "In this table you can set reverb levels for audio zones. For a medium-sized (e.g., 100 square meter) meeting room, try a decay time of around 1.5 seconds and a wet/dry mix of 25%. For an airplane hangar or cathedral, try a decay time of 4 seconds and a wet/dry mix of 50%.",
|
"help": "In this table you can set reverb levels for audio zones. For a medium-sized (e.g., 100 square meter) meeting room, try a decay time of around 1.5 seconds and a wet/dry mix of 25%. For an airplane hangar or cathedral, try a decay time of 4 seconds and a wet/dry mix of 50%.",
|
||||||
"numbered": true,
|
"numbered": true,
|
||||||
|
"content_setting": true,
|
||||||
"can_add_new_rows": true,
|
"can_add_new_rows": true,
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
|
|
7
domain-server/resources/web/base-settings-scripts.html
Normal file
7
domain-server/resources/web/base-settings-scripts.html
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<script src='/js/underscore-min.js'></script>
|
||||||
|
<script src='/js/underscore-keypath.min.js'></script>
|
||||||
|
<script src='/js/bootbox.min.js'></script>
|
||||||
|
<script src='/js/form2js.min.js'></script>
|
||||||
|
<script src='/js/bootstrap-switch.min.js'></script>
|
||||||
|
<script src='/js/shared.js'></script>
|
||||||
|
<script src='/js/base-settings.js'></script>
|
51
domain-server/resources/web/base-settings.html
Normal file
51
domain-server/resources/web/base-settings.html
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<div class="col-md-10 col-md-offset-1 col-xs-12">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<div class="alert" style="display:none;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<div id="cloud-domains-alert" class="alert alert-info alert-dismissible" role="alert" style="display: none;">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<span class="alert-link">
|
||||||
|
<a href="https://highfidelity.com/user/cloud_domains" target="_blank" class="blue-link">Visit Cloud Hosted Domains</a> to manage all your cloud domains
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form id="settings-form" role="form">
|
||||||
|
<script id="panels-template" type="text/template">
|
||||||
|
<% _.each(descriptions, function(group){ %>
|
||||||
|
<% if (!group.hidden) { %>
|
||||||
|
|
||||||
|
<% var settings = _.partition(group.settings, function(value, index) { %>
|
||||||
|
<% return !value.deprecated %>
|
||||||
|
<% })[0] %>
|
||||||
|
|
||||||
|
<% isGrouped = !!group.name %>
|
||||||
|
<% panelID = isGrouped ? group.name : group.html_id %>
|
||||||
|
|
||||||
|
<div id="<%- panelID %>_group" class="anchor"></div>
|
||||||
|
<div class="panel panel-default<%- (isGrouped) ? ' grouped' : '' %>"
|
||||||
|
id="<%- panelID %>">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title"><%- group.label %></h3>
|
||||||
|
<span class="badge"></span>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<% _.each(settings, function(setting) { %>
|
||||||
|
<% keypath = isGrouped ? group.name + "." + setting.name : setting.name %>
|
||||||
|
<%= getFormGroup(keypath, setting, values, false) %>
|
||||||
|
<% }); %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
<% }); %>
|
||||||
|
</script>
|
||||||
|
<div id="panels"></div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,45 +1,19 @@
|
||||||
<!--#include virtual="header.html"-->
|
<!--#include virtual="header.html"-->
|
||||||
|
|
||||||
<div class="col-md-10 col-md-offset-1">
|
<script type="text/javascript">
|
||||||
<div class="row">
|
var Settings = {
|
||||||
<div class="col-xs-12">
|
content_settings: true,
|
||||||
<div class="alert" style="display:none;"></div>
|
endpoint: "/content-settings.json",
|
||||||
</div>
|
path: "/content/"
|
||||||
</div>
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
<div class="row">
|
<!--#include virtual="base-settings.html"-->
|
||||||
<div class="col-xs-12">
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h3 class="panel-title">Upload Entities File</h3>
|
|
||||||
</div>
|
|
||||||
<form id="upload-form" action="upload" enctype="multipart/form-data" method="post">
|
|
||||||
<div class="panel-body">
|
|
||||||
<p>
|
|
||||||
Upload an entities file (e.g.: models.json.gz) to replace the content of this domain.<br>
|
|
||||||
Note: <strong>Your domain's content will be replaced by the content you upload</strong>, but the backup files of your domain's content will not immediately be changed.
|
|
||||||
</p>
|
|
||||||
<p>If your domain has any content that you would like to re-use at a later date, save a manual backup of your models.json.gz file, which is usually stored at the following paths:</p>
|
|
||||||
<label class="control-label">Windows</label>
|
|
||||||
<pre>C:/Users/[username]/AppData/Roaming/High Fidelity/assignment-client/entities/models.json.gz</pre>
|
|
||||||
<label class="control-label">OSX</label>
|
|
||||||
<pre>/Users/[username]/Library/Application Support/High Fidelity/assignment-client/entities/models.json.gz</pre>
|
|
||||||
<label class="control-label">Linux</label>
|
|
||||||
<pre>/home/[username]/.local/share/High Fidelity/assignment-client/entities/models.json.gz</pre>
|
|
||||||
<br>
|
|
||||||
<input type="file" name="entities-file" class="form-control-file" accept=".json, .gz">
|
|
||||||
<br>
|
|
||||||
</div>
|
|
||||||
<div class="panel-footer">
|
|
||||||
<input type="submit" class="btn btn-info" value="Upload">
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--#include virtual="footer.html"-->
|
<!--#include virtual="footer.html"-->
|
||||||
<script src='js/content.js'></script>
|
|
||||||
<script src='/js/sweetalert.min.js'></script>
|
<!--#include virtual="base-settings-scripts.html"-->
|
||||||
|
|
||||||
|
<script src="js/content.js"></script>
|
||||||
|
|
||||||
<!--#include virtual="page-end.html"-->
|
<!--#include virtual="page-end.html"-->
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
|
|
||||||
|
Settings.afterReloadActions = function() {};
|
||||||
|
|
||||||
function showSpinnerAlert(title) {
|
function showSpinnerAlert(title) {
|
||||||
swal({
|
swal({
|
||||||
title: title,
|
title: title,
|
||||||
|
|
|
@ -18,6 +18,14 @@ body {
|
||||||
margin-top: 70px;
|
margin-top: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* unfortunate hack so that anchors go to the right place with fixed navbar */
|
||||||
|
:target:before {
|
||||||
|
content: " ";
|
||||||
|
display: block;
|
||||||
|
height: 70px;
|
||||||
|
margin-top: -70px;
|
||||||
|
}
|
||||||
|
|
||||||
[hidden] {
|
[hidden] {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
@ -345,3 +353,75 @@ table .headers + .headers td {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
ul.nav li.dropdown-on-hover:hover ul.dropdown-menu {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.nav li.dropdown ul.dropdown-menu {
|
||||||
|
padding: 0px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.nav li.dropdown li a {
|
||||||
|
padding-top: 7px;
|
||||||
|
padding-bottom: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.nav li.dropdown li a:hover {
|
||||||
|
color: white;
|
||||||
|
background-color: #337ab7;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.nav li.dropdown ul.dropdown-menu .divider {
|
||||||
|
margin: 0px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#visit-domain-link {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-btn {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#save-settings-xs-button {
|
||||||
|
float: right;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#button-bars {
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#hamburger-badge {
|
||||||
|
position: relative;
|
||||||
|
top: -2px;
|
||||||
|
float: left;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#restart-server {
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#restart-server:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#visit-hmd-icon {
|
||||||
|
width: 25px;
|
||||||
|
position: relative;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
|
|
@ -17,30 +17,47 @@
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<!-- Brand and toggle get grouped for better mobile display -->
|
<!-- Brand and toggle get grouped for better mobile display -->
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#collapsed-navbar">
|
||||||
<span class="sr-only">Toggle navigation</span>
|
<span class="sr-only">Toggle navigation</span>
|
||||||
<span class="icon-bar"></span>
|
<span id="hamburger-badge" class="badge"></span>
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
<div id="button-bars">
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button id="save-settings-xs-button" class="save-button btn btn-success navbar-btn hidden-sm hidden-md hidden-lg" role="button" style="display: none;" disabled>Save</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
<div class="collapse navbar-collapse" id="collapsed-navbar">
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li><a href="/">Nodes</a></li>
|
<li><a href="/">Nodes</a></li>
|
||||||
<li class="dropdown">
|
<li><a href="/assignment">Assignment</a></li>
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Assignments <span class="caret"></span></a>
|
|
||||||
<ul class="dropdown-menu" role="menu">
|
<li class="dropdown dropdown-on-hover">
|
||||||
<li><a href="/assignment">New Assignment</a></li>
|
<a href="/content/" class="hidden-xs">Content <span class="content-settings-badge badge"></span> <span class="caret"></span></a>
|
||||||
</ul>
|
<a href="#" class="dropdown-toggle hidden-sm hidden-md hidden-lg" data-toggle="dropdown">Content <span class="content-badge badge"></span> <span class="caret"></span></a>
|
||||||
|
<ul id="content-settings-nav-dropdown" class="dropdown-menu" role="menu">
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="dropdown dropdown-on-hover">
|
||||||
|
<a href="/settings/" class="hidden-xs">Settings <span class="domain-settings-badge badge"></span> <span class="caret"></span></a>
|
||||||
|
<a href="#" class="dropdown-toggle hidden-sm hidden-md hidden-lg" data-toggle="dropdown">Settings <span class="domain-settings-badge badge"></span> <span class="caret"></span></a>
|
||||||
|
<ul id="domain-settings-nav-dropdown" class="dropdown-menu" role="menu">
|
||||||
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="/content/">Content</a></li>
|
|
||||||
<li><a href="/settings/">Settings</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="nav navbar-right navbar-nav">
|
<ul class="nav navbar-right navbar-nav">
|
||||||
<li><a id="visit-domain-link" class="blue-link" target="_blank" style="display: none;">Visit domain in VR</a></li>
|
<a id="visit-domain-link" class="btn btn-default navbar-btn" role="button" target="_blank" style="display: none;">
|
||||||
<li><a href="#" id="restart-server"><span class="glyphicon glyphicon-refresh"></span> Restart</a></li>
|
<img id="visit-hmd-icon" src="/images/hmd-w-eyes.svg" alt="Head-mounted display" />
|
||||||
|
Visit in VR
|
||||||
|
</a>
|
||||||
|
<button id="save-settings-button" class="save-button btn btn-success navbar-btn hidden-xs" role="button" style="display: none;" disabled>Save</button>
|
||||||
|
<a href="#" id="restart-server" class="navbar-btn btn btn-link"><span class="glyphicon glyphicon-refresh"></span> Restart</a>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div><!-- /.container-fluid -->
|
</div><!-- /.container-fluid -->
|
||||||
|
|
10
domain-server/resources/web/images/hmd-w-eyes.svg
Normal file
10
domain-server/resources/web/images/hmd-w-eyes.svg
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 456 244" style="enable-background:new 0 0 456 244;" xml:space="preserve">
|
||||||
|
<path d="M352.8,3.4h-250C49.6,3.4,6.3,46.2,6.3,98.9v44.9c0,52.7,43.3,95.5,96.5,95.5h67.6c19.4,0,31.9-17.9,42.9-33.6
|
||||||
|
c4.2-6.1,11.1-15.9,14.8-17.9c3.6,2.1,10.4,12.2,14.5,18.4c10.4,15.5,22.1,33.1,40.3,33.1h69.9c53.3,0,96.5-42.9,96.5-95.5V98.9
|
||||||
|
C449.3,46.2,406,3.4,352.8,3.4z M129.6,157.6c-22.4,0-40.6-18.2-40.6-40.6s18.2-40.6,40.6-40.6c22.4,0,40.6,18.2,40.6,40.6
|
||||||
|
S151.9,157.6,129.6,157.6z M328.4,157.6c-22.4,0-40.6-18.2-40.6-40.6s18.2-40.6,40.6-40.6c22.4,0,40.6,18.2,40.6,40.6
|
||||||
|
S350.8,157.6,328.4,157.6z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 862 B |
1140
domain-server/resources/web/js/base-settings.js
Normal file
1140
domain-server/resources/web/js/base-settings.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -23,16 +23,22 @@ function showRestartModal() {
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function settingsGroupAnchor(base, html_id) {
|
||||||
|
return base + "#" + html_id + "_group"
|
||||||
|
}
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
var url = window.location;
|
var url = window.location;
|
||||||
|
|
||||||
// Will only work if string in href matches with location
|
// Will only work if string in href matches with location
|
||||||
$('ul.nav a[href="'+ url +'"]').parent().addClass('active');
|
$('ul.nav a[href="'+ url +'"]').parent().addClass('active');
|
||||||
|
|
||||||
// Will also work for relative and absolute hrefs
|
// Will also work for relative and absolute hrefs
|
||||||
$('ul.nav a').filter(function() {
|
$('ul.nav a').filter(function() {
|
||||||
return this.href == url;
|
return this.href == url;
|
||||||
}).parent().addClass('active');
|
}).parent().addClass('active');
|
||||||
$('body').on('click', '#restart-server', function(e) {
|
|
||||||
|
$('body').on('click', '#restart-server', function(e) {
|
||||||
swal( {
|
swal( {
|
||||||
title: "Are you sure?",
|
title: "Are you sure?",
|
||||||
text: "This will restart your domain server, causing your domain to be briefly offline.",
|
text: "This will restart your domain server, causing your domain to be briefly offline.",
|
||||||
|
@ -45,4 +51,35 @@ $(document).ready(function(){
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var $contentDropdown = $('#content-settings-nav-dropdown');
|
||||||
|
var $settingsDropdown = $('#domain-settings-nav-dropdown');
|
||||||
|
|
||||||
|
// for pages that have the settings dropdowns
|
||||||
|
if ($contentDropdown.length && $settingsDropdown.length) {
|
||||||
|
// make a JSON request to get the dropdown menus for content and settings
|
||||||
|
// we don't error handle here because the top level menu is still clickable and usables if this fails
|
||||||
|
$.getJSON('/settings-menu-groups.json', function(data){
|
||||||
|
function makeGroupDropdownElement(group, base) {
|
||||||
|
var html_id = group.html_id ? group.html_id : group.name;
|
||||||
|
return "<li class='setting-group'><a href='" + settingsGroupAnchor(base, html_id) + "'>" + group.label + "<span class='badge'></span></a></li>";
|
||||||
|
}
|
||||||
|
|
||||||
|
$.each(data.content_settings, function(index, group){
|
||||||
|
if (index > 0) {
|
||||||
|
$contentDropdown.append("<li role='separator' class='divider'></li>");
|
||||||
|
}
|
||||||
|
|
||||||
|
$contentDropdown.append(makeGroupDropdownElement(group, "/content/"));
|
||||||
|
});
|
||||||
|
|
||||||
|
$.each(data.domain_settings, function(index, group){
|
||||||
|
if (index > 0) {
|
||||||
|
$settingsDropdown.append("<li role='separator' class='divider'></li>");
|
||||||
|
}
|
||||||
|
|
||||||
|
$settingsDropdown.append(makeGroupDropdownElement(group, "/settings/"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
var Settings = {
|
Object.assign(Settings, {
|
||||||
showAdvanced: false,
|
|
||||||
ADVANCED_CLASS: 'advanced-setting',
|
|
||||||
DEPRECATED_CLASS: 'deprecated-setting',
|
DEPRECATED_CLASS: 'deprecated-setting',
|
||||||
TRIGGER_CHANGE_CLASS: 'trigger-change',
|
TRIGGER_CHANGE_CLASS: 'trigger-change',
|
||||||
DATA_ROW_CLASS: 'value-row',
|
DATA_ROW_CLASS: 'value-row',
|
||||||
|
@ -41,7 +39,7 @@ var Settings = {
|
||||||
FORM_ID: 'settings-form',
|
FORM_ID: 'settings-form',
|
||||||
INVALID_ROW_CLASS: 'invalid-input',
|
INVALID_ROW_CLASS: 'invalid-input',
|
||||||
DATA_ROW_INDEX: 'data-row-index'
|
DATA_ROW_INDEX: 'data-row-index'
|
||||||
};
|
});
|
||||||
|
|
||||||
var URLs = {
|
var URLs = {
|
||||||
// STABLE METAVERSE_URL: https://metaverse.highfidelity.com
|
// STABLE METAVERSE_URL: https://metaverse.highfidelity.com
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,104 +1,21 @@
|
||||||
<!--#include virtual="header.html"-->
|
<!--#include virtual="header.html"-->
|
||||||
|
|
||||||
<div class="col-md-10 col-md-offset-1">
|
<script type="text/javascript">
|
||||||
<div class="row">
|
var Settings = {
|
||||||
<div class="col-md-12">
|
content_settings: false,
|
||||||
<div class="alert" style="display:none;"></div>
|
endpoint: "/settings.json",
|
||||||
</div>
|
path: "/settings/"
|
||||||
</div>
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
<div class="row">
|
<!--#include virtual="base-settings.html"-->
|
||||||
<div class="col-md-3 col-sm-3" id="setup-sidebar-col">
|
|
||||||
<div id="setup-sidebar" data-clampedwidth="#setup-sidebar-col">
|
|
||||||
<script id="list-group-template" type="text/template">
|
|
||||||
<% _.each(descriptions, function(group){ %>
|
|
||||||
<% if (!group.hidden) { %>
|
|
||||||
<% panelID = group.name ? group.name : group.html_id %>
|
|
||||||
<li>
|
|
||||||
<a href="#<%- panelID %>" class="list-group-item">
|
|
||||||
<span class="badge"></span>
|
|
||||||
<%- group.label %>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<% } %>
|
|
||||||
<% }); %>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<ul class="nav nav-pills nav-stacked">
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<button id="advanced-toggle-button" class="btn btn-info advanced-toggle">Show advanced</button>
|
|
||||||
<button class="btn btn-success save-button" disabled>Save</button>
|
|
||||||
<div id="manage-cloud-domains-link" style="display: none;">
|
|
||||||
<a href="https://highfidelity.com/user/cloud_domains" target="_blank" class="blue-link">Manage Cloud Hosted Domains</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-9 col-sm-9 col-xs-12">
|
|
||||||
<div class="col-xs-12">
|
|
||||||
|
|
||||||
<div id="cloud-domains-alert" class="alert alert-info alert-dismissible" role="alert" style="display: none;">
|
|
||||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
|
||||||
<span class="alert-link">
|
|
||||||
<a href="https://highfidelity.com/user/cloud_domains" target="_blank" class="blue-link">Visit Cloud Hosted Domains</a> to manage all your cloud domains
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form id="settings-form" role="form">
|
|
||||||
|
|
||||||
<script id="panels-template" type="text/template">
|
|
||||||
<% _.each(descriptions, function(group){ %>
|
|
||||||
<% if (!group.hidden) { %>
|
|
||||||
<% var settings = _.partition(group.settings, function(value, index) { return !value.deprecated })[0] %>
|
|
||||||
<% split_settings = _.partition(settings, function(value, index) { return !value.advanced }) %>
|
|
||||||
<% isAdvanced = _.isEmpty(split_settings[0]) && !_.isEmpty(split_settings[1]) %>
|
|
||||||
<% if (isAdvanced) { %>
|
|
||||||
<% $("a[href=#" + group.name + "]").addClass('advanced-setting').hide() %>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<% isGrouped = !!group.name %>
|
|
||||||
<% panelID = isGrouped ? group.name : group.html_id %>
|
|
||||||
|
|
||||||
<div class="panel panel-default<%- (isAdvanced) ? ' advanced-setting' : '' %><%- (isGrouped) ? ' grouped' : '' %>"
|
|
||||||
id="<%- panelID %>">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h3 class="panel-title"><%- group.label %></h3>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<% _.each(split_settings[0], function(setting) { %>
|
|
||||||
<% keypath = isGrouped ? group.name + "." + setting.name : setting.name %>
|
|
||||||
<%= getFormGroup(keypath, setting, values, false) %>
|
|
||||||
<% }); %>
|
|
||||||
<% if (!_.isEmpty(split_settings[1])) { %>
|
|
||||||
<% $("#advanced-toggle-button").show() %>
|
|
||||||
<% _.each(split_settings[1], function(setting) { %>
|
|
||||||
<% keypath = isGrouped ? group.name + "." + setting.name : setting.name %>
|
|
||||||
<%= getFormGroup(keypath, setting, values, true) %>
|
|
||||||
<% }); %>
|
|
||||||
<% }%>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<% } %>
|
|
||||||
<% }); %>
|
|
||||||
</script>
|
|
||||||
<div id="panels"></div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-xs-12 hidden-sm hidden-md hidden-lg">
|
|
||||||
<button class="btn btn-success save-button" id="small-save-button">Save</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--#include virtual="footer.html"-->
|
<!--#include virtual="footer.html"-->
|
||||||
<script src='/js/underscore-min.js'></script>
|
|
||||||
<script src='/js/underscore-keypath.min.js'></script>
|
|
||||||
<script src='/js/bootbox.min.js'></script>
|
|
||||||
<script src='/js/sha256.js'></script>
|
<script src='/js/sha256.js'></script>
|
||||||
<script src='js/form2js.min.js'></script>
|
|
||||||
<script src='js/bootstrap-switch.min.js'></script>
|
<!--#include virtual="base-settings-scripts.html"-->
|
||||||
<script src='/js/shared.js'></script>
|
|
||||||
<script src='js/settings.js'></script>
|
<script src="js/settings.js"></script>
|
||||||
|
|
||||||
<!--#include virtual="page-end.html"-->
|
<!--#include virtual="page-end.html"-->
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -501,7 +501,7 @@ void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) {
|
||||||
// store the new domain ID and auto network setting immediately
|
// store the new domain ID and auto network setting immediately
|
||||||
QString newSettingsJSON = QString("{\"metaverse\": { \"id\": \"%1\", \"automatic_networking\": \"full\"}}").arg(id);
|
QString newSettingsJSON = QString("{\"metaverse\": { \"id\": \"%1\", \"automatic_networking\": \"full\"}}").arg(id);
|
||||||
auto settingsDocument = QJsonDocument::fromJson(newSettingsJSON.toUtf8());
|
auto settingsDocument = QJsonDocument::fromJson(newSettingsJSON.toUtf8());
|
||||||
_settingsManager.recurseJSONObjectAndOverwriteSettings(settingsDocument.object());
|
_settingsManager.recurseJSONObjectAndOverwriteSettings(settingsDocument.object(), DomainSettings);
|
||||||
|
|
||||||
// store the new ID and auto networking setting on disk
|
// store the new ID and auto networking setting on disk
|
||||||
_settingsManager.persistToFile();
|
_settingsManager.persistToFile();
|
||||||
|
|
|
@ -39,8 +39,10 @@ const QString SETTINGS_DESCRIPTION_RELATIVE_PATH = "/resources/describe-settings
|
||||||
const QString DESCRIPTION_SETTINGS_KEY = "settings";
|
const QString DESCRIPTION_SETTINGS_KEY = "settings";
|
||||||
const QString SETTING_DEFAULT_KEY = "default";
|
const QString SETTING_DEFAULT_KEY = "default";
|
||||||
const QString DESCRIPTION_NAME_KEY = "name";
|
const QString DESCRIPTION_NAME_KEY = "name";
|
||||||
|
const QString DESCRIPTION_GROUP_LABEL_KEY = "label";
|
||||||
const QString SETTING_DESCRIPTION_TYPE_KEY = "type";
|
const QString SETTING_DESCRIPTION_TYPE_KEY = "type";
|
||||||
const QString DESCRIPTION_COLUMNS_KEY = "columns";
|
const QString DESCRIPTION_COLUMNS_KEY = "columns";
|
||||||
|
const QString CONTENT_SETTING_FLAG_KEY = "content_setting";
|
||||||
|
|
||||||
const QString SETTINGS_VIEWPOINT_KEY = "viewpoint";
|
const QString SETTINGS_VIEWPOINT_KEY = "viewpoint";
|
||||||
|
|
||||||
|
@ -63,6 +65,8 @@ DomainServerSettingsManager::DomainServerSettingsManager() {
|
||||||
|
|
||||||
if (descriptionObject.contains(DESCRIPTION_SETTINGS_KEY)) {
|
if (descriptionObject.contains(DESCRIPTION_SETTINGS_KEY)) {
|
||||||
_descriptionArray = descriptionDocument.object()[DESCRIPTION_SETTINGS_KEY].toArray();
|
_descriptionArray = descriptionDocument.object()[DESCRIPTION_SETTINGS_KEY].toArray();
|
||||||
|
splitSettingsDescription();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,6 +82,91 @@ DomainServerSettingsManager::DomainServerSettingsManager() {
|
||||||
Q_ARG(int, MISSING_SETTINGS_DESC_ERROR_CODE));
|
Q_ARG(int, MISSING_SETTINGS_DESC_ERROR_CODE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DomainServerSettingsManager::splitSettingsDescription() {
|
||||||
|
// construct separate description arrays for domain settings and content settings
|
||||||
|
// since they are displayed on different pages
|
||||||
|
|
||||||
|
// along the way we also construct one object that holds the groups separated by domain settings
|
||||||
|
// and content settings, so that the DS can setup dropdown menus below "Content" and "Settings"
|
||||||
|
// headers to jump directly to a settings group on the page of either
|
||||||
|
QJsonArray domainSettingsMenuGroups;
|
||||||
|
QJsonArray contentSettingsMenuGroups;
|
||||||
|
|
||||||
|
foreach(const QJsonValue& group, _descriptionArray) {
|
||||||
|
QJsonObject groupObject = group.toObject();
|
||||||
|
|
||||||
|
static const QString HIDDEN_GROUP_KEY = "hidden";
|
||||||
|
bool groupHidden = groupObject.contains(HIDDEN_GROUP_KEY) && groupObject[HIDDEN_GROUP_KEY].toBool();
|
||||||
|
|
||||||
|
QJsonArray domainSettingArray;
|
||||||
|
QJsonArray contentSettingArray;
|
||||||
|
|
||||||
|
foreach(const QJsonValue& settingDescription, groupObject[DESCRIPTION_SETTINGS_KEY].toArray()) {
|
||||||
|
QJsonObject settingDescriptionObject = settingDescription.toObject();
|
||||||
|
|
||||||
|
bool isContentSetting = settingDescriptionObject.contains(CONTENT_SETTING_FLAG_KEY)
|
||||||
|
&& settingDescriptionObject[CONTENT_SETTING_FLAG_KEY].toBool();
|
||||||
|
|
||||||
|
if (isContentSetting) {
|
||||||
|
// push the setting description to the pending content setting array
|
||||||
|
contentSettingArray.push_back(settingDescriptionObject);
|
||||||
|
} else {
|
||||||
|
// push the setting description to the pending domain setting array
|
||||||
|
domainSettingArray.push_back(settingDescriptionObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!domainSettingArray.isEmpty() || !contentSettingArray.isEmpty()) {
|
||||||
|
|
||||||
|
// we know for sure we'll have something to add to our settings menu groups
|
||||||
|
// so setup that object for the group now, as long as the group isn't hidden alltogether
|
||||||
|
QJsonObject settingsDropdownGroup;
|
||||||
|
|
||||||
|
if (!groupHidden) {
|
||||||
|
settingsDropdownGroup[DESCRIPTION_NAME_KEY] = groupObject[DESCRIPTION_NAME_KEY];
|
||||||
|
settingsDropdownGroup[DESCRIPTION_GROUP_LABEL_KEY] = groupObject[DESCRIPTION_GROUP_LABEL_KEY];
|
||||||
|
|
||||||
|
static const QString DESCRIPTION_GROUP_HTML_ID_KEY = "html_id";
|
||||||
|
if (groupObject.contains(DESCRIPTION_GROUP_HTML_ID_KEY)) {
|
||||||
|
settingsDropdownGroup[DESCRIPTION_GROUP_HTML_ID_KEY] = groupObject[DESCRIPTION_GROUP_HTML_ID_KEY];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!domainSettingArray.isEmpty()) {
|
||||||
|
// we have some domain settings from this group, add the group with the filtered settings
|
||||||
|
QJsonObject filteredGroupObject = groupObject;
|
||||||
|
filteredGroupObject[DESCRIPTION_SETTINGS_KEY] = domainSettingArray;
|
||||||
|
_domainSettingsDescription.push_back(filteredGroupObject);
|
||||||
|
|
||||||
|
// if the group isn't hidden, add its information to the domain settings menu groups
|
||||||
|
if (!groupHidden) {
|
||||||
|
domainSettingsMenuGroups.push_back(settingsDropdownGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contentSettingArray.isEmpty()) {
|
||||||
|
// we have some content settings from this group, add the group with the filtered settings
|
||||||
|
QJsonObject filteredGroupObject = groupObject;
|
||||||
|
filteredGroupObject[DESCRIPTION_SETTINGS_KEY] = contentSettingArray;
|
||||||
|
_contentSettingsDescription.push_back(filteredGroupObject);
|
||||||
|
|
||||||
|
// if the group isn't hidden, add its information to the content settings menu groups
|
||||||
|
if (!groupHidden) {
|
||||||
|
contentSettingsMenuGroups.push_back(settingsDropdownGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// populate the settings menu groups with what we've collected
|
||||||
|
|
||||||
|
static const QString SPLIT_MENU_GROUPS_DOMAIN_SETTINGS_KEY = "domain_settings";
|
||||||
|
static const QString SPLIT_MENU_GROUPS_CONTENT_SETTINGS_KEY = "content_settings";
|
||||||
|
|
||||||
|
_settingsMenuGroups[SPLIT_MENU_GROUPS_DOMAIN_SETTINGS_KEY] = domainSettingsMenuGroups;
|
||||||
|
_settingsMenuGroups[SPLIT_MENU_GROUPS_CONTENT_SETTINGS_KEY] = contentSettingsMenuGroups;
|
||||||
|
}
|
||||||
|
|
||||||
void DomainServerSettingsManager::processSettingsRequestPacket(QSharedPointer<ReceivedMessage> message) {
|
void DomainServerSettingsManager::processSettingsRequestPacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
Assignment::Type type;
|
Assignment::Type type;
|
||||||
message->readPrimitive(&type);
|
message->readPrimitive(&type);
|
||||||
|
@ -986,48 +1075,72 @@ QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QStrin
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection *connection, const QUrl &url) {
|
bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection *connection, const QUrl &url) {
|
||||||
if (connection->requestOperation() == QNetworkAccessManager::PostOperation && url.path() == SETTINGS_PATH_JSON) {
|
if (connection->requestOperation() == QNetworkAccessManager::PostOperation) {
|
||||||
// this is a POST operation to change one or more settings
|
if (url.path() == SETTINGS_PATH_JSON || url.path() == CONTENT_SETTINGS_PATH_JSON) {
|
||||||
QJsonDocument postedDocument = QJsonDocument::fromJson(connection->requestContent());
|
// this is a POST operation to change one or more settings
|
||||||
QJsonObject postedObject = postedDocument.object();
|
QJsonDocument postedDocument = QJsonDocument::fromJson(connection->requestContent());
|
||||||
|
QJsonObject postedObject = postedDocument.object();
|
||||||
|
|
||||||
// we recurse one level deep below each group for the appropriate setting
|
SettingsType endpointType = url.path() == SETTINGS_PATH_JSON ? DomainSettings : ContentSettings;
|
||||||
bool restartRequired = recurseJSONObjectAndOverwriteSettings(postedObject);
|
|
||||||
|
|
||||||
// store whatever the current _settingsMap is to file
|
// we recurse one level deep below each group for the appropriate setting
|
||||||
persistToFile();
|
bool restartRequired = recurseJSONObjectAndOverwriteSettings(postedObject, endpointType);
|
||||||
|
|
||||||
// return success to the caller
|
// store whatever the current _settingsMap is to file
|
||||||
QString jsonSuccess = "{\"status\": \"success\"}";
|
persistToFile();
|
||||||
connection->respond(HTTPConnection::StatusCode200, jsonSuccess.toUtf8(), "application/json");
|
|
||||||
|
|
||||||
// defer a restart to the domain-server, this gives our HTTPConnection enough time to respond
|
// return success to the caller
|
||||||
if (restartRequired) {
|
QString jsonSuccess = "{\"status\": \"success\"}";
|
||||||
const int DOMAIN_SERVER_RESTART_TIMER_MSECS = 1000;
|
connection->respond(HTTPConnection::StatusCode200, jsonSuccess.toUtf8(), "application/json");
|
||||||
QTimer::singleShot(DOMAIN_SERVER_RESTART_TIMER_MSECS, qApp, SLOT(restart()));
|
|
||||||
} else {
|
// defer a restart to the domain-server, this gives our HTTPConnection enough time to respond
|
||||||
unpackPermissions();
|
if (restartRequired) {
|
||||||
apiRefreshGroupInformation();
|
const int DOMAIN_SERVER_RESTART_TIMER_MSECS = 1000;
|
||||||
emit updateNodePermissions();
|
QTimer::singleShot(DOMAIN_SERVER_RESTART_TIMER_MSECS, qApp, SLOT(restart()));
|
||||||
emit settingsUpdated();
|
} else {
|
||||||
|
unpackPermissions();
|
||||||
|
apiRefreshGroupInformation();
|
||||||
|
emit updateNodePermissions();
|
||||||
|
emit settingsUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
} else if (connection->requestOperation() == QNetworkAccessManager::GetOperation) {
|
||||||
|
static const QString SETTINGS_MENU_GROUPS_PATH = "/settings-menu-groups.json";
|
||||||
|
|
||||||
return true;
|
if (url.path() == SETTINGS_PATH_JSON || url.path() == CONTENT_SETTINGS_PATH_JSON) {
|
||||||
} else if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == SETTINGS_PATH_JSON) {
|
|
||||||
// setup a JSON Object with descriptions and non-omitted settings
|
|
||||||
const QString SETTINGS_RESPONSE_DESCRIPTION_KEY = "descriptions";
|
|
||||||
const QString SETTINGS_RESPONSE_VALUE_KEY = "values";
|
|
||||||
|
|
||||||
QJsonObject rootObject;
|
// setup a JSON Object with descriptions and non-omitted settings
|
||||||
rootObject[SETTINGS_RESPONSE_DESCRIPTION_KEY] = _descriptionArray;
|
const QString SETTINGS_RESPONSE_DESCRIPTION_KEY = "descriptions";
|
||||||
rootObject[SETTINGS_RESPONSE_VALUE_KEY] = responseObjectForType("", true);
|
const QString SETTINGS_RESPONSE_VALUE_KEY = "values";
|
||||||
connection->respond(HTTPConnection::StatusCode200, QJsonDocument(rootObject).toJson(), "application/json");
|
|
||||||
|
QJsonObject rootObject;
|
||||||
|
|
||||||
|
bool forDomainSettings = (url.path() == SETTINGS_PATH_JSON);
|
||||||
|
bool forContentSettings = (url.path() == CONTENT_SETTINGS_PATH_JSON);;
|
||||||
|
|
||||||
|
rootObject[SETTINGS_RESPONSE_DESCRIPTION_KEY] = forDomainSettings
|
||||||
|
? _domainSettingsDescription : _contentSettingsDescription;
|
||||||
|
|
||||||
|
// grab a domain settings object for all types, filtered for the right class of settings
|
||||||
|
rootObject[SETTINGS_RESPONSE_VALUE_KEY] = responseObjectForType("", true, forDomainSettings, forContentSettings);
|
||||||
|
|
||||||
|
connection->respond(HTTPConnection::StatusCode200, QJsonDocument(rootObject).toJson(), "application/json");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else if (url.path() == SETTINGS_MENU_GROUPS_PATH) {
|
||||||
|
connection->respond(HTTPConnection::StatusCode200, QJsonDocument(_settingsMenuGroups).toJson(), "application/json");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject DomainServerSettingsManager::responseObjectForType(const QString& typeValue, bool isAuthenticated) {
|
QJsonObject DomainServerSettingsManager::responseObjectForType(const QString& typeValue, bool isAuthenticated,
|
||||||
|
bool includeDomainSettings, bool includeContentSettings) {
|
||||||
QJsonObject responseObject;
|
QJsonObject responseObject;
|
||||||
|
|
||||||
if (!typeValue.isEmpty() || isAuthenticated) {
|
if (!typeValue.isEmpty() || isAuthenticated) {
|
||||||
|
@ -1036,8 +1149,15 @@ QJsonObject DomainServerSettingsManager::responseObjectForType(const QString& ty
|
||||||
|
|
||||||
const QString AFFECTED_TYPES_JSON_KEY = "assignment-types";
|
const QString AFFECTED_TYPES_JSON_KEY = "assignment-types";
|
||||||
|
|
||||||
|
QJsonArray& filteredDescriptionArray = _descriptionArray;
|
||||||
|
if (includeDomainSettings && !includeContentSettings) {
|
||||||
|
filteredDescriptionArray = _domainSettingsDescription;
|
||||||
|
} else if (includeContentSettings && !includeDomainSettings) {
|
||||||
|
filteredDescriptionArray = _contentSettingsDescription;
|
||||||
|
}
|
||||||
|
|
||||||
// enumerate the groups in the description object to find which settings to pass
|
// enumerate the groups in the description object to find which settings to pass
|
||||||
foreach(const QJsonValue& groupValue, _descriptionArray) {
|
foreach(const QJsonValue& groupValue, filteredDescriptionArray) {
|
||||||
QJsonObject groupObject = groupValue.toObject();
|
QJsonObject groupObject = groupValue.toObject();
|
||||||
QString groupKey = groupObject[DESCRIPTION_NAME_KEY].toString();
|
QString groupKey = groupObject[DESCRIPTION_NAME_KEY].toString();
|
||||||
QJsonArray groupSettingsArray = groupObject[DESCRIPTION_SETTINGS_KEY].toArray();
|
QJsonArray groupSettingsArray = groupObject[DESCRIPTION_SETTINGS_KEY].toArray();
|
||||||
|
@ -1045,10 +1165,13 @@ QJsonObject DomainServerSettingsManager::responseObjectForType(const QString& ty
|
||||||
QJsonObject groupResponseObject;
|
QJsonObject groupResponseObject;
|
||||||
|
|
||||||
foreach(const QJsonValue& settingValue, groupSettingsArray) {
|
foreach(const QJsonValue& settingValue, groupSettingsArray) {
|
||||||
|
|
||||||
const QString VALUE_HIDDEN_FLAG_KEY = "value-hidden";
|
const QString VALUE_HIDDEN_FLAG_KEY = "value-hidden";
|
||||||
|
|
||||||
QJsonObject settingObject = settingValue.toObject();
|
QJsonObject settingObject = settingValue.toObject();
|
||||||
|
|
||||||
|
// consider this setting as long as it isn't hidden
|
||||||
|
// and we've been asked to include this type (domain setting or content setting)
|
||||||
if (!settingObject[VALUE_HIDDEN_FLAG_KEY].toBool()) {
|
if (!settingObject[VALUE_HIDDEN_FLAG_KEY].toBool()) {
|
||||||
QJsonArray affectedTypesArray = settingObject[AFFECTED_TYPES_JSON_KEY].toArray();
|
QJsonArray affectedTypesArray = settingObject[AFFECTED_TYPES_JSON_KEY].toArray();
|
||||||
if (affectedTypesArray.isEmpty()) {
|
if (affectedTypesArray.isEmpty()) {
|
||||||
|
@ -1212,7 +1335,8 @@ QJsonObject DomainServerSettingsManager::settingDescriptionFromGroup(const QJson
|
||||||
return QJsonObject();
|
return QJsonObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject) {
|
bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject,
|
||||||
|
SettingsType settingsType) {
|
||||||
static const QString SECURITY_ROOT_KEY = "security";
|
static const QString SECURITY_ROOT_KEY = "security";
|
||||||
static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist";
|
static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist";
|
||||||
static const QString BROADCASTING_KEY = "broadcasting";
|
static const QString BROADCASTING_KEY = "broadcasting";
|
||||||
|
@ -1222,6 +1346,8 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
||||||
auto& settingsVariant = _configMap.getConfig();
|
auto& settingsVariant = _configMap.getConfig();
|
||||||
bool needRestart = false;
|
bool needRestart = false;
|
||||||
|
|
||||||
|
auto& filteredDescriptionArray = settingsType == DomainSettings ? _domainSettingsDescription : _contentSettingsDescription;
|
||||||
|
|
||||||
// Iterate on the setting groups
|
// Iterate on the setting groups
|
||||||
foreach(const QString& rootKey, postedObject.keys()) {
|
foreach(const QString& rootKey, postedObject.keys()) {
|
||||||
const QJsonValue& rootValue = postedObject[rootKey];
|
const QJsonValue& rootValue = postedObject[rootKey];
|
||||||
|
@ -1236,7 +1362,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
||||||
QJsonObject groupDescriptionObject;
|
QJsonObject groupDescriptionObject;
|
||||||
|
|
||||||
// we need to check the description array to see if this is a root setting or a group setting
|
// we need to check the description array to see if this is a root setting or a group setting
|
||||||
foreach(const QJsonValue& groupValue, _descriptionArray) {
|
foreach(const QJsonValue& groupValue, filteredDescriptionArray) {
|
||||||
if (groupValue.toObject()[DESCRIPTION_NAME_KEY] == rootKey) {
|
if (groupValue.toObject()[DESCRIPTION_NAME_KEY] == rootKey) {
|
||||||
// we matched a group - keep this since we'll use it below to update the settings
|
// we matched a group - keep this since we'll use it below to update the settings
|
||||||
groupDescriptionObject = groupValue.toObject();
|
groupDescriptionObject = groupValue.toObject();
|
||||||
|
@ -1269,6 +1395,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
||||||
|
|
||||||
if (!matchingDescriptionObject.isEmpty()) {
|
if (!matchingDescriptionObject.isEmpty()) {
|
||||||
updateSetting(rootKey, rootValue, *thisMap, matchingDescriptionObject);
|
updateSetting(rootKey, rootValue, *thisMap, matchingDescriptionObject);
|
||||||
|
|
||||||
if (rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY &&
|
if (rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY &&
|
||||||
rootKey != SETTINGS_PATHS_KEY && rootKey != WIZARD_KEY) {
|
rootKey != SETTINGS_PATHS_KEY && rootKey != WIZARD_KEY) {
|
||||||
needRestart = true;
|
needRestart = true;
|
||||||
|
@ -1286,6 +1413,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
||||||
if (!matchingDescriptionObject.isEmpty()) {
|
if (!matchingDescriptionObject.isEmpty()) {
|
||||||
const QJsonValue& settingValue = rootValue.toObject()[settingKey];
|
const QJsonValue& settingValue = rootValue.toObject()[settingKey];
|
||||||
updateSetting(settingKey, settingValue, *thisMap, matchingDescriptionObject);
|
updateSetting(settingKey, settingValue, *thisMap, matchingDescriptionObject);
|
||||||
|
|
||||||
if ((rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY &&
|
if ((rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY &&
|
||||||
rootKey != DESCRIPTION_ROOT_KEY && rootKey != WIZARD_KEY) ||
|
rootKey != DESCRIPTION_ROOT_KEY && rootKey != WIZARD_KEY) ||
|
||||||
settingKey == AC_SUBNET_WHITELIST_KEY) {
|
settingKey == AC_SUBNET_WHITELIST_KEY) {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#define hifi_DomainServerSettingsManager_h
|
#define hifi_DomainServerSettingsManager_h
|
||||||
|
|
||||||
#include <QtCore/QJsonArray>
|
#include <QtCore/QJsonArray>
|
||||||
|
#include <QtCore/QJsonObject>
|
||||||
#include <QtCore/QJsonDocument>
|
#include <QtCore/QJsonDocument>
|
||||||
#include <QtNetwork/QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ const QString SETTINGS_PATHS_KEY = "paths";
|
||||||
|
|
||||||
const QString SETTINGS_PATH = "/settings";
|
const QString SETTINGS_PATH = "/settings";
|
||||||
const QString SETTINGS_PATH_JSON = SETTINGS_PATH + ".json";
|
const QString SETTINGS_PATH_JSON = SETTINGS_PATH + ".json";
|
||||||
|
const QString CONTENT_SETTINGS_PATH_JSON = "/content-settings.json";
|
||||||
const QString AGENT_STANDARD_PERMISSIONS_KEYPATH = "security.standard_permissions";
|
const QString AGENT_STANDARD_PERMISSIONS_KEYPATH = "security.standard_permissions";
|
||||||
const QString AGENT_PERMISSIONS_KEYPATH = "security.permissions";
|
const QString AGENT_PERMISSIONS_KEYPATH = "security.permissions";
|
||||||
const QString IP_PERMISSIONS_KEYPATH = "security.ip_permissions";
|
const QString IP_PERMISSIONS_KEYPATH = "security.ip_permissions";
|
||||||
|
@ -38,6 +40,10 @@ const QString GROUP_FORBIDDENS_KEYPATH = "security.group_forbiddens";
|
||||||
|
|
||||||
using GroupByUUIDKey = QPair<QUuid, QUuid>; // groupID, rankID
|
using GroupByUUIDKey = QPair<QUuid, QUuid>; // groupID, rankID
|
||||||
|
|
||||||
|
enum SettingsType {
|
||||||
|
DomainSettings,
|
||||||
|
ContentSettings
|
||||||
|
};
|
||||||
|
|
||||||
class DomainServerSettingsManager : public QObject {
|
class DomainServerSettingsManager : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -123,8 +129,10 @@ private slots:
|
||||||
private:
|
private:
|
||||||
QStringList _argumentList;
|
QStringList _argumentList;
|
||||||
|
|
||||||
QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false);
|
QJsonArray filteredDescriptionArray(bool isContentSettings);
|
||||||
bool recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject);
|
QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false,
|
||||||
|
bool includeDomainSettings = true, bool includeContentSettings = true);
|
||||||
|
bool recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, SettingsType settingsType);
|
||||||
|
|
||||||
void updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap,
|
void updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap,
|
||||||
const QJsonObject& settingDescription);
|
const QJsonObject& settingDescription);
|
||||||
|
@ -132,8 +140,15 @@ private:
|
||||||
void sortPermissions();
|
void sortPermissions();
|
||||||
void persistToFile();
|
void persistToFile();
|
||||||
|
|
||||||
|
void splitSettingsDescription();
|
||||||
|
|
||||||
double _descriptionVersion;
|
double _descriptionVersion;
|
||||||
|
|
||||||
QJsonArray _descriptionArray;
|
QJsonArray _descriptionArray;
|
||||||
|
QJsonArray _domainSettingsDescription;
|
||||||
|
QJsonArray _contentSettingsDescription;
|
||||||
|
QJsonObject _settingsMenuGroups;
|
||||||
|
|
||||||
HifiConfigVariantMap _configMap;
|
HifiConfigVariantMap _configMap;
|
||||||
|
|
||||||
friend class DomainServer;
|
friend class DomainServer;
|
||||||
|
|
|
@ -79,7 +79,7 @@ bool HTTPManager::handleHTTPRequest(HTTPConnection* connection, const QUrl& url,
|
||||||
QHash<QByteArray, QByteArray> redirectHeader;
|
QHash<QByteArray, QByteArray> redirectHeader;
|
||||||
redirectHeader.insert(QByteArray("Location"), redirectLocation.toUtf8());
|
redirectHeader.insert(QByteArray("Location"), redirectLocation.toUtf8());
|
||||||
|
|
||||||
connection->respond(HTTPConnection::StatusCode301, "", HTTPConnection::DefaultContentType, redirectHeader);
|
connection->respond(HTTPConnection::StatusCode302, "", HTTPConnection::DefaultContentType, redirectHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the last thing is a trailing slash then we want to look for index file
|
// if the last thing is a trailing slash then we want to look for index file
|
||||||
|
|
Loading…
Reference in a new issue