mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-07 13:12:39 +02:00
Update domain server settings
Move requests that require access token to go through DS Update various styling and ease of use on DS settings page Update domain server settings CP CP
This commit is contained in:
parent
f21a284324
commit
7dc475c695
9 changed files with 567 additions and 61 deletions
|
@ -14,7 +14,8 @@
|
|||
{
|
||||
"name": "id",
|
||||
"label": "Domain ID",
|
||||
"help": "This is your High Fidelity domain ID. If you do not want your domain to be registered in the High Fidelity metaverse you can leave this blank."
|
||||
"help": "This is your High Fidelity domain ID. If you do not want your domain to be registered in the High Fidelity metaverse you can leave this blank.",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "automatic_networking",
|
||||
|
@ -1513,4 +1514,4 @@
|
|||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
body {
|
||||
position: relative;
|
||||
padding-bottom: 30px;
|
||||
margin-top: 70px;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
|
@ -81,7 +82,7 @@ span.port {
|
|||
|
||||
#setup-sidebar.affix {
|
||||
position: fixed;
|
||||
top: 15px;
|
||||
top: 70px;
|
||||
}
|
||||
|
||||
#setup-sidebar button {
|
||||
|
@ -255,3 +256,26 @@ table .headers + .headers td {
|
|||
-webkit-transform: scale(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
/* From https://gist.github.com/alexandrevicenzi/680147013e902a4eaa5d */
|
||||
.glyphicon-refresh-animate {
|
||||
-animation: spin .7s infinite linear;
|
||||
-ms-animation: spin .7s infinite linear;
|
||||
-webkit-animation: spinw .7s infinite linear;
|
||||
-moz-animation: spinm .7s infinite linear;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from { transform: scale(1) rotate(0deg);}
|
||||
to { transform: scale(1) rotate(360deg);}
|
||||
}
|
||||
|
||||
@-webkit-keyframes spinw {
|
||||
from { -webkit-transform: rotate(0deg);}
|
||||
to { -webkit-transform: rotate(360deg);}
|
||||
}
|
||||
|
||||
@-moz-keyframes spinm {
|
||||
from { -moz-transform: rotate(0deg);}
|
||||
to { -moz-transform: rotate(360deg);}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<script src='/js/sweetalert.min.js'></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-default" role="navigation">
|
||||
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
|
||||
<div class="container-fluid">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header">
|
||||
|
@ -23,7 +23,7 @@
|
|||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="/">domain-server</a>
|
||||
<!--<a class="navbar-brand" href="/">domain-server</a>-->
|
||||
</div>
|
||||
|
||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||
|
|
|
@ -32,7 +32,6 @@ $(document).ready(function(){
|
|||
$('ul.nav a').filter(function() {
|
||||
return this.href == url;
|
||||
}).parent().addClass('active');
|
||||
|
||||
$('body').on('click', '#restart-server', function(e) {
|
||||
swal( {
|
||||
title: "Are you sure?",
|
||||
|
@ -46,4 +45,4 @@ $(document).ready(function(){
|
|||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-sm-3" id="setup-sidebar-col">
|
||||
<div id="setup-sidebar" class="hidden-xs" data-spy="affix" data-offset-top="55" data-clampedwidth="#setup-sidebar-col">
|
||||
<div id="setup-sidebar" class="hidden-xs" data-spy="affix" data-offset-top="1" data-clampedwidth="#setup-sidebar-col">
|
||||
<script id="list-group-template" type="text/template">
|
||||
<% _.each(descriptions, function(group){ %>
|
||||
<% panelID = group.name ? group.name : group.html_id %>
|
||||
|
@ -26,7 +26,7 @@
|
|||
</ul>
|
||||
|
||||
<button id="advanced-toggle-button" class="btn btn-info advanced-toggle">Show advanced</button>
|
||||
<button class="btn btn-success save-button">Save</button>
|
||||
<button class="btn btn-success save-button" disabled>Save</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
|||
</div>
|
||||
|
||||
<div class="col-xs-12">
|
||||
|
||||
<form id="settings-form" role="form">
|
||||
|
||||
<script id="panels-template" type="text/template">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
var Settings = {
|
||||
showAdvanced: false,
|
||||
METAVERSE_URL: 'https://metaverse.highfidelity.com',
|
||||
METAVERSE_URL: 'https://staging.highfidelity.com',
|
||||
ADVANCED_CLASS: 'advanced-setting',
|
||||
DEPRECATED_CLASS: 'deprecated-setting',
|
||||
TRIGGER_CHANGE_CLASS: 'trigger-change',
|
||||
|
@ -38,6 +38,7 @@ var Settings = {
|
|||
DOMAIN_ID_SELECTOR: '[name="metaverse.id"]',
|
||||
ACCESS_TOKEN_SELECTOR: '[name="metaverse.access_token"]',
|
||||
PLACES_TABLE_ID: 'places-table',
|
||||
ADD_PLACE_BTN_ID: 'add-place-btn',
|
||||
FORM_ID: 'settings-form',
|
||||
INVALID_ROW_CLASS: 'invalid-input',
|
||||
DATA_ROW_INDEX: 'data-row-index'
|
||||
|
@ -469,13 +470,14 @@ function setupHFAccountButton() {
|
|||
// without an access token niether of them can do anything
|
||||
$("[data-keypath='metaverse.id']").hide();
|
||||
$("[data-keypath='metaverse.automatic_networking']").hide();
|
||||
|
||||
// use the existing getFormGroup helper to ask for a button
|
||||
var buttonGroup = viewHelpers.getFormGroup('', buttonSetting, Settings.data.values);
|
||||
|
||||
// add the button group to the top of the metaverse panel
|
||||
$('#metaverse .panel-body').prepend(buttonGroup);
|
||||
}
|
||||
|
||||
// use the existing getFormGroup helper to ask for a button
|
||||
var buttonGroup = viewHelpers.getFormGroup('', buttonSetting, Settings.data.values);
|
||||
|
||||
// add the button group to the top of the metaverse panel
|
||||
$('#metaverse .panel-body').prepend(buttonGroup);
|
||||
}
|
||||
|
||||
function disonnectHighFidelityAccount() {
|
||||
|
@ -516,6 +518,8 @@ function prepareAccessTokenPrompt() {
|
|||
// we have an input value - set the access token input with this and save settings
|
||||
$(Settings.ACCESS_TOKEN_SELECTOR).val(inputValue).change();
|
||||
|
||||
console.log("Prepping access token prompt");
|
||||
|
||||
// if the user doesn't have a domain ID set, give them the option to create one now
|
||||
if (!Settings.data.values.metaverse.id) {
|
||||
// show domain ID selection alert
|
||||
|
@ -589,38 +593,36 @@ function showDomainCreationAlert(justConnected) {
|
|||
function createNewDomainID(description, justConnected) {
|
||||
// get the JSON object ready that we'll use to create a new domain
|
||||
var domainJSON = {
|
||||
"domain": {
|
||||
"private_description": description
|
||||
},
|
||||
"access_token": $(Settings.ACCESS_TOKEN_SELECTOR).val()
|
||||
"private_description": description
|
||||
//"access_token": $(Settings.ACCESS_TOKEN_SELECTOR).val()
|
||||
}
|
||||
|
||||
$.post(Settings.METAVERSE_URL + "/api/v1/domains", domainJSON, function(data){
|
||||
if (data.status == "success") {
|
||||
// we successfully created a domain ID, set it on that field
|
||||
var domainID = data.domain.id;
|
||||
$(Settings.DOMAIN_ID_SELECTOR).val(domainID).change();
|
||||
//$.post(Settings.METAVERSE_URL + "/api/v1/domains", domainJSON, function(data){
|
||||
$.post("/api/domain", domainJSON, function(data){
|
||||
// we successfully created a domain ID, set it on that field
|
||||
var domainID = data.domain_id;
|
||||
console.log("Setting domain id to ", data, domainID);
|
||||
$(Settings.DOMAIN_ID_SELECTOR).val(domainID).change();
|
||||
|
||||
if (justConnected) {
|
||||
var successText = "We connnected your High Fidelity account and created a new domain ID for this machine."
|
||||
} else {
|
||||
var successText = "We created a new domain ID for this machine."
|
||||
}
|
||||
|
||||
successText += "</br></br>Click the button below to save your new settings and restart your domain-server.";
|
||||
|
||||
// show a sweet alert to say we are all finished up and that we need to save
|
||||
swal({
|
||||
title: 'Success!',
|
||||
type: 'success',
|
||||
text: successText,
|
||||
html: true,
|
||||
confirmButtonText: 'Save'
|
||||
}, function(){
|
||||
saveSettings();
|
||||
});
|
||||
if (justConnected) {
|
||||
var successText = "We connnected your High Fidelity account and created a new domain ID for this machine."
|
||||
} else {
|
||||
var successText = "We created a new domain ID for this machine."
|
||||
}
|
||||
}).fail(function(){
|
||||
|
||||
successText += "</br></br>Click the button below to save your new settings and restart your domain-server.";
|
||||
|
||||
// show a sweet alert to say we are all finished up and that we need to save
|
||||
swal({
|
||||
title: 'Success!',
|
||||
type: 'success',
|
||||
text: successText,
|
||||
html: true,
|
||||
confirmButtonText: 'Save'
|
||||
}, function(){
|
||||
saveSettings();
|
||||
});
|
||||
}, 'json').fail(function(){
|
||||
|
||||
var errorText = "There was a problem creating your new domain ID. Do you want to try again or";
|
||||
|
||||
|
@ -665,6 +667,7 @@ function setupPlacesTable() {
|
|||
+ " go to the <a href='" + Settings.METAVERSE_URL + "/user/places'>My Places</a> "
|
||||
+ "page in your High Fidelity Metaverse account.",
|
||||
read_only: true,
|
||||
can_add_new_rows: false,
|
||||
columns: [
|
||||
{
|
||||
"name": "name",
|
||||
|
@ -672,10 +675,10 @@ function setupPlacesTable() {
|
|||
},
|
||||
{
|
||||
"name": "path",
|
||||
"label": "Path"
|
||||
"label": "Viewpoint or Path"
|
||||
},
|
||||
{
|
||||
"name": "edit",
|
||||
"name": "remove",
|
||||
"label": "",
|
||||
"class": "buttons"
|
||||
}
|
||||
|
@ -688,6 +691,12 @@ function setupPlacesTable() {
|
|||
// append the places table in the right place
|
||||
$('#places_paths .panel-body').prepend(placesTableGroup);
|
||||
|
||||
|
||||
var spinner = '<p id="loading-places-spinner" class="text-center" style="display: none">';
|
||||
spinner += '<span class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span>';
|
||||
spinner += '</p>';
|
||||
$('#' + Settings.PLACES_TABLE_ID).after($(spinner));
|
||||
|
||||
// do we have a domain ID?
|
||||
if (Settings.data.values.metaverse.id.length > 0) {
|
||||
// now, ask the API for what places, if any, point to this domain
|
||||
|
@ -700,22 +709,50 @@ function setupPlacesTable() {
|
|||
|
||||
}
|
||||
|
||||
function placeTableRow(name, path, isTemporary) {
|
||||
function placeTableRow(name, path, isTemporary, placeID) {
|
||||
var name_link = "<a href='hifi://" + name + "'>" + (isTemporary ? name + " (temporary)" : name) + "</a>";
|
||||
|
||||
if (isTemporary) {
|
||||
var editColumn = "<td class='buttons'></td>";
|
||||
} else {
|
||||
var editColumn = "<td class='buttons'><a class='glyphicon glyphicon-pencil'"
|
||||
+ " href='" + Settings.METAVERSE_URL + "/user/places/" + name + "/edit" + "'</a></td>";
|
||||
function placeEditClicked() {
|
||||
editHighFidelityPlace(placeID, name, path);
|
||||
}
|
||||
|
||||
return "<tr><td>" + name_link + "</td><td>" + path + "</td>" + editColumn + "</tr>";
|
||||
function placeDeleteClicked() {
|
||||
var el = $(this);
|
||||
var dialog = bootbox.confirm("Are you sure you want to remove <strong>" + name + "</strong>?", function(result) {
|
||||
if (result) {
|
||||
sendUpdatePlaceRequest(
|
||||
placeID,
|
||||
'',
|
||||
true,
|
||||
function() {
|
||||
reloadPlacesOrTemporaryName();
|
||||
dialog.modal('hide');
|
||||
}, function() {
|
||||
dialog.modal('hide');
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if (isTemporary) {
|
||||
var editLink = "";
|
||||
var deleteColumn = "<td class='buttons'></td>";
|
||||
} else {
|
||||
var editLink = " <a class='place-edit' href='javascript:void(0);'>Edit</a>";
|
||||
var deleteColumn = "<td class='buttons'><a class='place-delete glyphicon glyphicon-remove'></a></td>";
|
||||
}
|
||||
|
||||
var row = $("<tr><td>" + name_link + "</td><td>" + path + editLink + "</td>" + deleteColumn + "</tr>");
|
||||
row.find(".place-edit").click(placeEditClicked);
|
||||
row.find(".place-delete").click(placeDeleteClicked);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
function placeTableRowForPlaceObject(place) {
|
||||
var placePathOrIndex = (place.path ? place.path : "/");
|
||||
return placeTableRow(place.name, placePathOrIndex, false);
|
||||
return placeTableRow(place.name, placePathOrIndex, false, place.id);
|
||||
}
|
||||
|
||||
function getDomainFromAPI(callback) {
|
||||
|
@ -729,7 +766,12 @@ function getDomainFromAPI(callback) {
|
|||
}
|
||||
|
||||
function reloadPlacesOrTemporaryName() {
|
||||
$('#' + Settings.PLACES_TABLE_ID + " tbody tr").not('.headers').remove();
|
||||
$('#loading-places-spinner').show();
|
||||
|
||||
getDomainFromAPI(function(data){
|
||||
$('#loading-places-spinner').hide();
|
||||
|
||||
// check if we have owner_places (for a real domain) or a name (for a temporary domain)
|
||||
if (data.status == "success") {
|
||||
if (data.domain.owner_places) {
|
||||
|
@ -741,6 +783,18 @@ function reloadPlacesOrTemporaryName() {
|
|||
// add a table row for this temporary domain name
|
||||
$('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRow(data.domain.name, '/', true));
|
||||
}
|
||||
|
||||
var row = $("<tr> <td></td> <td></td> <td class='buttons'><a href='javascript:void(0);' class='place-add glyphicon glyphicon-plus'></a></td> </tr>");
|
||||
|
||||
row.find(".place-add").click(function(ev) {
|
||||
chooseFromHighFidelityPlaces(null, function() {
|
||||
reloadPlacesOrTemporaryName();
|
||||
});
|
||||
});
|
||||
|
||||
$('#' + Settings.PLACES_TABLE_ID + " tbody").append(row);
|
||||
} else {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -757,19 +811,208 @@ function appendDomainIDButtons() {
|
|||
domainIDInput.after(createButton);
|
||||
}
|
||||
|
||||
function showDomainSettingsModal(clickedButton) {
|
||||
bootbox.dialog({
|
||||
title: "Choose matching place",
|
||||
message: modal_body,
|
||||
buttons: modal_buttons
|
||||
})
|
||||
}
|
||||
|
||||
function sendUpdatePlaceRequest(id, path, clearDomainID, onSuccess, onFail) {
|
||||
var data = {
|
||||
place_id: id,
|
||||
path: path
|
||||
};
|
||||
if (clearDomainID) {
|
||||
data.domain_id = null;
|
||||
}
|
||||
$.ajax({
|
||||
url: '/api/places',
|
||||
type: 'PUT',
|
||||
data: data,
|
||||
success: onSuccess,
|
||||
fail: onFail
|
||||
});
|
||||
}
|
||||
|
||||
function editHighFidelityPlace(placeID, name, path) {
|
||||
|
||||
var dialog;
|
||||
|
||||
var modal_body = "<div class='form-group'>";
|
||||
modal_body += "<input type='text' id='place-path-input' class='form-control' value='" + path + "'>";
|
||||
modal_body += "</div>";
|
||||
|
||||
var modal_buttons = {};
|
||||
modal_buttons["success"] = {
|
||||
label: 'Save',
|
||||
callback: function() {
|
||||
var placePath = $('#place-path-input').val();
|
||||
|
||||
if (path == placePath) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$(this).attr('disabled', 'disabled');
|
||||
|
||||
sendUpdatePlaceRequest(
|
||||
placeID,
|
||||
placePath,
|
||||
false,
|
||||
function(data) {
|
||||
dialog.modal('hide')
|
||||
reloadPlacesOrTemporaryName();
|
||||
},
|
||||
function(data) {
|
||||
dialog.modal('hide')
|
||||
}
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
dialog = bootbox.dialog({
|
||||
title: "Modify Viewpoint or Path for <strong>" + name + "</strong>",
|
||||
message: modal_body,
|
||||
buttons: modal_buttons
|
||||
})
|
||||
}
|
||||
|
||||
function showLoadingDialog() {
|
||||
var message = '<p class="text-center">';
|
||||
message += '<span class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span> Loading your places...';
|
||||
message += '</p>';
|
||||
|
||||
return bootbox.dialog({
|
||||
message: message,
|
||||
closeButton: false
|
||||
});
|
||||
}
|
||||
|
||||
function chooseFromHighFidelityPlaces(forcePathTo, onSuccessfullyAdded) {
|
||||
if (Settings.initialValues.metaverse.access_token) {
|
||||
|
||||
var loadingDialog = showLoadingDialog();
|
||||
|
||||
$.ajax("/api/places", {
|
||||
dataType: 'json',
|
||||
jsonp: false,
|
||||
success: function(data) {
|
||||
loadingDialog.modal('hide');
|
||||
console.log(data);
|
||||
if (data.status == 'success') {
|
||||
var modal_buttons = {
|
||||
cancel: {
|
||||
label: 'Cancel',
|
||||
className: 'btn-default'
|
||||
}
|
||||
};
|
||||
|
||||
var dialog;
|
||||
var modal_body;
|
||||
|
||||
if (data.data.places.length) {
|
||||
// setup a select box for the returned places
|
||||
modal_body = "<p>Choose the High Fidelity place to point at this domain server.</p>";
|
||||
place_select = $("<select id='place-name-select' class='form-control'></select>");
|
||||
_.each(data.data.places, function(place) {
|
||||
place_select.append("<option value='" + place.id + "'>" + place.name + "</option>");
|
||||
})
|
||||
modal_body += "<label for='place-name-select'>Places</label>" + place_select[0].outerHTML
|
||||
|
||||
if (forcePathTo === undefined || forcePathTo === null) {
|
||||
modal_body += "<div class='form-group'>";
|
||||
modal_body += "<label for='place-path-input' class='control-label'>Path</label>";
|
||||
modal_body += "<input type='text' id='place-path-input' class='form-control' value='/'>";
|
||||
modal_body += "</div>";
|
||||
}
|
||||
|
||||
modal_buttons["success"] = {
|
||||
label: 'Choose place',
|
||||
callback: function() {
|
||||
var placeID = $('#place-name-select').val()
|
||||
// set the place ID on the form
|
||||
$(Settings.place_ID_SELECTOR).val(placeID).change();
|
||||
|
||||
if (forcePathTo === undefined) {
|
||||
var placePath = $('#place-path-input').val();
|
||||
} else {
|
||||
var placePath = forcePathTo;
|
||||
}
|
||||
|
||||
$(this).attr('disabled', 'disabled');
|
||||
|
||||
sendUpdatePlaceRequest(
|
||||
placeID,
|
||||
placePath,
|
||||
true,
|
||||
function(data) {
|
||||
dialog.modal('hide')
|
||||
if (onSuccessfullyAdded) {
|
||||
onSuccessfullyAdded();
|
||||
}
|
||||
},
|
||||
function(data) {
|
||||
bootbox.alert('There was an error adding this place name');
|
||||
}
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
modal_buttons["success"] = {
|
||||
label: 'Create new place',
|
||||
callback: function() {
|
||||
window.open(Settings.METAVERSE_URL + "/user/places", '_blank');
|
||||
}
|
||||
}
|
||||
modal_body = "<p>You do not have any places in your High Fidelity account." +
|
||||
"<br/><br/>Go to your <a href='https://metaverse.highfidelity.com/user/places/new'>places page</a> to create a new one. Once your place is created re-open this dialog to select it.</p>"
|
||||
}
|
||||
|
||||
dialog = bootbox.dialog({
|
||||
title: "Choose the place to point at this domain server",
|
||||
message: modal_body,
|
||||
buttons: modal_buttons
|
||||
});
|
||||
} else {
|
||||
bootbox.alert("We were unable to load your place names. Please try again later.");
|
||||
}
|
||||
},
|
||||
fail: function() {
|
||||
loadingDialog.modal('hide');
|
||||
bootbox.alert("Failed to retrieve your places from the High Fidelity Metaverse");
|
||||
console.log("FAILURE TO GET JSON");
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
bootbox.alert({
|
||||
message: "You must have an access token to query your High Fidelity places.<br><br>" +
|
||||
"Please follow the instructions on the settings page to add an access token.",
|
||||
title: "Access token required"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function chooseFromHighFidelityDomains(clickedButton) {
|
||||
// setup the modal to help user pick their domain
|
||||
if (Settings.initialValues.metaverse.access_token) {
|
||||
|
||||
// add a spinner to the choose button
|
||||
clickedButton.html("Loading domains...")
|
||||
clickedButton.attr('disabled', 'disabled')
|
||||
clickedButton.html("Loading domains...");
|
||||
clickedButton.attr('disabled', 'disabled');
|
||||
|
||||
// get a list of user domains from data-web
|
||||
data_web_domains_url = Settings.METAVERSE_URL + "/api/v1/domains?access_token="
|
||||
$.getJSON(data_web_domains_url + Settings.initialValues.metaverse.access_token, function(data){
|
||||
data_web_domains_url = Settings.METAVERSE_URL + "/api/v1/domains?access_token=";
|
||||
data_web_domains_url += Settings.initialValues.metaverse.access_token;
|
||||
data_web_domains_url = "/api/domains";
|
||||
$.getJSON(data_web_domains_url, function(data){
|
||||
|
||||
modal_buttons = {
|
||||
var modal_buttons = {
|
||||
cancel: {
|
||||
label: 'Cancel',
|
||||
className: 'btn-default'
|
||||
|
@ -778,8 +1021,8 @@ function chooseFromHighFidelityDomains(clickedButton) {
|
|||
|
||||
if (data.data.domains.length) {
|
||||
// setup a select box for the returned domains
|
||||
modal_body = "<p>Choose the High Fidelity domain you want this domain-server to represent.<br/>This will set your domain ID on the settings page.</p>"
|
||||
domain_select = $("<select id='domain-name-select' class='form-control'></select>")
|
||||
modal_body = "<p>Choose the High Fidelity domain you want this domain-server to represent.<br/>This will set your domain ID on the settings page.</p>";
|
||||
domain_select = $("<select id='domain-name-select' class='form-control'></select>");
|
||||
_.each(data.data.domains, function(domain){
|
||||
var domainString = "";
|
||||
|
||||
|
@ -1356,6 +1599,7 @@ function getDescriptionForKey(key) {
|
|||
var SAVE_BUTTON_LABEL_SAVE = "Save";
|
||||
var SAVE_BUTTON_LABEL_RESTART = "Save and restart";
|
||||
var reasonsForRestart = [];
|
||||
var numChangesBySection = {};
|
||||
|
||||
function badgeSidebarForDifferences(changedElement) {
|
||||
// figure out which group this input is in
|
||||
|
@ -1405,6 +1649,20 @@ function badgeSidebarForDifferences(changedElement) {
|
|||
badgeValue = ""
|
||||
}
|
||||
|
||||
numChangesBySection[panelParentID] = badgeValue;
|
||||
|
||||
var hasChanges = badgeValue > 0;
|
||||
|
||||
if (!hasChanges) {
|
||||
for (var key in numChangesBySection) {
|
||||
if (numChangesBySection[key] > 0) {
|
||||
hasChanges = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(".save-button").prop("disabled", !hasChanges);
|
||||
$(".save-button").html(reasonsForRestart.length > 0 ? SAVE_BUTTON_LABEL_RESTART : SAVE_BUTTON_LABEL_SAVE);
|
||||
$("a[href='#" + panelParentID + "'] .badge").html(badgeValue);
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#include "DomainServerNodeData.h"
|
||||
#include "NodeConnectionData.h"
|
||||
|
||||
static const QString BASE_METAVERSE_URL = "https://staging.highfidelity.com";
|
||||
|
||||
int const DomainServer::EXIT_CODE_REBOOT = 234923;
|
||||
|
||||
#if USE_STABLE_GLOBAL_SERVICES
|
||||
|
@ -339,6 +341,7 @@ bool DomainServer::optionallySetupOAuth() {
|
|||
|
||||
const QVariantMap& settingsMap = _settingsManager.getSettingsMap();
|
||||
_oauthProviderURL = QUrl(settingsMap.value(OAUTH_PROVIDER_URL_OPTION).toString());
|
||||
qDebug() << "OAUTH: " << _oauthProviderURL;
|
||||
|
||||
// if we don't have an oauth provider URL then we default to the default node auth url
|
||||
if (_oauthProviderURL.isEmpty()) {
|
||||
|
@ -1731,8 +1734,11 @@ QString DomainServer::pathForRedirect(QString path) const {
|
|||
return "http://" + _hostname + ":" + QString::number(_httpManager.serverPort()) + path;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const QString URI_OAUTH = "/oauth";
|
||||
bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {
|
||||
qDebug() << "HTTP request received at" << connection->requestOperation() << url.toString();
|
||||
const QString JSON_MIME_TYPE = "application/json";
|
||||
|
||||
const QString URI_ASSIGNMENT = "/assignment";
|
||||
|
@ -1740,6 +1746,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
const QString URI_SETTINGS = "/settings";
|
||||
const QString URI_ENTITY_FILE_UPLOAD = "/content/upload";
|
||||
const QString URI_RESTART = "/restart";
|
||||
const QString URI_API_PLACES = "/api/places";
|
||||
const QString URI_API_DOMAIN = "/api/domain";
|
||||
|
||||
const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
||||
|
||||
|
@ -1899,6 +1907,56 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
connection->respond(HTTPConnection::StatusCode200);
|
||||
restart();
|
||||
return true;
|
||||
} else if (url.path() == URI_API_DOMAIN) {
|
||||
QUrl url { BASE_METAVERSE_URL + "/api/v1/domains" };
|
||||
|
||||
auto accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||
if (!accessTokenVariant->isValid()) {
|
||||
connection->respond(HTTPConnection::StatusCode400, "User access token has not been set");
|
||||
}
|
||||
|
||||
url.setQuery("access_token=" + accessTokenVariant->toString());
|
||||
|
||||
QNetworkRequest req(url);
|
||||
req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = NetworkAccessManager::getInstance().get(req);
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [reply, connection]() {
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
connection->respond(HTTPConnection::StatusCode500);
|
||||
return;
|
||||
}
|
||||
|
||||
static const char* CONTENT_TYPE_JSON { "application/json" };
|
||||
connection->respond(HTTPConnection::StatusCode200, reply->readAll());
|
||||
});
|
||||
return true;
|
||||
|
||||
} else if (url.path() == URI_API_PLACES) {
|
||||
QUrl url { BASE_METAVERSE_URL + "/api/v1/user/places" };
|
||||
|
||||
auto accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||
if (!accessTokenVariant->isValid()) {
|
||||
connection->respond(HTTPConnection::StatusCode400, "User access token has not been set");
|
||||
}
|
||||
|
||||
url.setQuery("access_token=" + accessTokenVariant->toString());
|
||||
|
||||
QNetworkRequest req(url);
|
||||
req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = NetworkAccessManager::getInstance().get(req);
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [reply, connection]() {
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
connection->respond(HTTPConnection::StatusCode500);
|
||||
return;
|
||||
}
|
||||
|
||||
static const char* CONTENT_TYPE_JSON { "application/json" };
|
||||
connection->respond(HTTPConnection::StatusCode200, reply->readAll());
|
||||
});
|
||||
return true;
|
||||
|
||||
} 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);
|
||||
|
@ -1992,8 +2050,144 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
connection->respond(HTTPConnection::StatusCode400);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} else if (url.path() == "/domain_settings") {
|
||||
auto accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||
if (!accessTokenVariant) {
|
||||
connection->respond(HTTPConnection::StatusCode400);
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (url.path() == URI_API_DOMAIN) {
|
||||
auto accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||
if (!accessTokenVariant) {
|
||||
connection->respond(HTTPConnection::StatusCode400, "User access token has not been set");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto params = connection->parseUrlEncodedForm();
|
||||
|
||||
auto it = params.find("private_description");
|
||||
if (it == params.end()) {
|
||||
connection->respond(HTTPConnection::StatusCode400);
|
||||
return true;
|
||||
}
|
||||
|
||||
QJsonObject root {
|
||||
{"access_token", accessTokenVariant->toString()},
|
||||
{"domain",
|
||||
QJsonObject({ { "private_description", it.value() } })
|
||||
}
|
||||
};
|
||||
QJsonDocument doc { root };
|
||||
|
||||
QUrl url { BASE_METAVERSE_URL + "/api/v1/domains" };
|
||||
QNetworkRequest req(url);
|
||||
req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
QNetworkReply* reply = NetworkAccessManager::getInstance().post(req, doc.toJson());
|
||||
connect(reply, &QNetworkReply::finished, this, [reply, connection]() {
|
||||
auto responseData = reply->readAll();
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
connection->respond(HTTPConnection::StatusCode500,
|
||||
"Error communicating with Metaverse");
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonParseError error;
|
||||
QJsonDocument response { QJsonDocument::fromJson(responseData, &error) };
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
connection->respond(HTTPConnection::StatusCode500,
|
||||
"Error communicating with Metaverse, bad response");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.isObject()) {
|
||||
connection->respond(HTTPConnection::StatusCode500,
|
||||
"Error communicating with Metaverse, unexpected response");
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject root {
|
||||
{ "domain_id", response.object()["domain"].toObject()["id"] },
|
||||
};
|
||||
|
||||
static const char* CONTENT_TYPE_JSON { "application/json" };
|
||||
connection->respond(HTTPConnection::StatusCode200, QJsonDocument(root).toJson(), CONTENT_TYPE_JSON);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if (connection->requestOperation() == QNetworkAccessManager::PutOperation) {
|
||||
if (url.path() == URI_API_PLACES) {
|
||||
auto params = connection->parseUrlEncodedForm();
|
||||
|
||||
auto it = params.find("place_id");
|
||||
if (it == params.end()) {
|
||||
connection->respond(HTTPConnection::StatusCode400);
|
||||
return true;
|
||||
}
|
||||
QString place_id = it.value();
|
||||
|
||||
it = params.find("path");
|
||||
if (it == params.end()) {
|
||||
connection->respond(HTTPConnection::StatusCode400);
|
||||
return true;
|
||||
}
|
||||
QString path = it.value();
|
||||
|
||||
it = params.find("domain_id");
|
||||
QString domain_id;
|
||||
if (it == params.end()) {
|
||||
QVariantMap& settingsMap = _settingsManager.getSettingsMap();
|
||||
domain_id = valueForKeyPath(settingsMap, METAVERSE_DOMAIN_ID_KEY_PATH)->toString();
|
||||
} else {
|
||||
domain_id = it.value();
|
||||
}
|
||||
|
||||
|
||||
QJsonObject root {
|
||||
{
|
||||
"place",
|
||||
QJsonObject({
|
||||
{ "pointee_query", domain_id },
|
||||
{ "path", path }
|
||||
})
|
||||
}
|
||||
};
|
||||
QJsonDocument doc(root);
|
||||
|
||||
|
||||
QUrl url { BASE_METAVERSE_URL + "/api/v1/places/" + place_id };
|
||||
|
||||
auto accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||
if (!accessTokenVariant->isValid()) {
|
||||
connection->respond(HTTPConnection::StatusCode400, "User access token has not been set");
|
||||
}
|
||||
|
||||
url.setQuery("access_token=" + accessTokenVariant->toString());
|
||||
|
||||
QNetworkRequest req(url);
|
||||
req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
QNetworkReply* reply = NetworkAccessManager::getInstance().put(req, doc.toJson());
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [reply, connection]() {
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
qDebug() << "Got error response from metaverse server: " << reply->readAll();
|
||||
connection->respond(HTTPConnection::StatusCode500,
|
||||
"Error communicating with Metaverse");
|
||||
return;
|
||||
}
|
||||
|
||||
static const char* CONTENT_TYPE_JSON { "application/json" };
|
||||
connection->respond(HTTPConnection::StatusCode200, reply->readAll());
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) {
|
||||
const QString ALL_NODE_DELETE_REGEX_STRING = QString("\\%1\\/?$").arg(URI_NODES);
|
||||
const QString NODE_DELETE_REGEX_STRING = QString("\\%1\\/(%2)\\/$").arg(URI_NODES).arg(UUID_REGEX_STRING);
|
||||
|
@ -2098,6 +2292,8 @@ HTTPSConnection* DomainServer::connectionFromReplyWithState(QNetworkReply* reply
|
|||
void DomainServer::tokenGrantFinished() {
|
||||
auto tokenReply = qobject_cast<QNetworkReply*>(sender());
|
||||
|
||||
qDebug() << "Token grant finsihed";
|
||||
|
||||
if (tokenReply) {
|
||||
if (tokenReply->error() == QNetworkReply::NoError) {
|
||||
// now that we have a token for this profile, send off a profile request
|
||||
|
@ -2129,6 +2325,7 @@ void DomainServer::profileRequestFinished() {
|
|||
|
||||
if (connection) {
|
||||
if (profileReply->error() == QNetworkReply::NoError) {
|
||||
qDebug() << "Reply: " << profileReply->readAll();
|
||||
// call helper method to get cookieHeaders
|
||||
Headers cookieHeaders = setupCookieHeadersFromProfileReply(profileReply);
|
||||
|
||||
|
@ -2298,6 +2495,8 @@ QNetworkReply* DomainServer::profileRequestGivenTokenReply(QNetworkReply* tokenR
|
|||
profileURL.setPath("/api/v1/user/profile");
|
||||
profileURL.setQuery(QString("%1=%2").arg(OAUTH_JSON_ACCESS_TOKEN_KEY, accessToken));
|
||||
|
||||
qDebug() << "Sending profile request to: " << profileURL;
|
||||
|
||||
QNetworkRequest profileRequest(profileURL);
|
||||
profileRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
profileRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "HTTPConnection.h"
|
||||
#include "EmbeddedWebserverLogging.h"
|
||||
#include "HTTPManager.h"
|
||||
#include <QUrlQuery>
|
||||
|
||||
const char* HTTPConnection::StatusCode200 = "200 OK";
|
||||
const char* HTTPConnection::StatusCode301 = "301 Moved Permanently";
|
||||
|
@ -52,10 +53,31 @@ HTTPConnection::~HTTPConnection() {
|
|||
}
|
||||
}
|
||||
|
||||
QHash<QString, QString> HTTPConnection::parseUrlEncodedForm() {
|
||||
// make sure we have the correct MIME type
|
||||
QList<QByteArray> elements = _requestHeaders.value("Content-Type").split(';');
|
||||
|
||||
QString contentType = elements.at(0).trimmed();
|
||||
if (contentType != "application/x-www-form-urlencoded") {
|
||||
return QHash<QString, QString>();
|
||||
}
|
||||
|
||||
QUrlQuery form { _requestContent };
|
||||
QHash<QString, QString> pairs;
|
||||
for (auto pair : form.queryItems()) {
|
||||
pairs[QUrl::fromPercentEncoding(pair.first.toLatin1())] = QUrl::fromPercentEncoding(pair.second.toLatin1());
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
|
||||
QList<FormData> HTTPConnection::parseFormData() const {
|
||||
// make sure we have the correct MIME type
|
||||
QList<QByteArray> elements = _requestHeaders.value("Content-Type").split(';');
|
||||
if (elements.at(0).trimmed() != "multipart/form-data") {
|
||||
|
||||
QString contentType = elements.at(0).trimmed();
|
||||
|
||||
if (contentType != "multipart/form-data") {
|
||||
return QList<FormData>();
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,8 @@ public:
|
|||
/// Parses the request content as form data, returning a list of header/content pairs.
|
||||
QList<FormData> parseFormData () const;
|
||||
|
||||
QHash<QString, QString> parseUrlEncodedForm();
|
||||
|
||||
/// Sends a response and closes the connection.
|
||||
void respond (const char* code, const QByteArray& content = QByteArray(),
|
||||
const char* contentType = DefaultContentType,
|
||||
|
|
Loading…
Reference in a new issue