diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json
index 93d703c8b3..427dc62520 100644
--- a/domain-server/resources/describe-settings.json
+++ b/domain-server/resources/describe-settings.json
@@ -1,5 +1,5 @@
{
- "version": 2.1,
+ "version": 2.2,
"settings": [
{
"name": "metaverse",
@@ -1321,73 +1321,6 @@
"default": "30000",
"advanced": true
},
- {
- "name": "backups",
- "type": "table",
- "label": "Backup Rules",
- "help": "In this table you can define a set of rules for how frequently to backup copies of your entites content file.",
- "numbered": false,
- "can_add_new_rows": true,
- "default": [
- {
- "Name": "Half Hourly Rolling",
- "backupInterval": 1800,
- "format": ".backup.halfhourly.%N",
- "maxBackupVersions": 5
- },
- {
- "Name": "Daily Rolling",
- "backupInterval": 86400,
- "format": ".backup.daily.%N",
- "maxBackupVersions": 7
- },
- {
- "Name": "Weekly Rolling",
- "backupInterval": 604800,
- "format": ".backup.weekly.%N",
- "maxBackupVersions": 4
- },
- {
- "Name": "Thirty Day Rolling",
- "backupInterval": 2592000,
- "format": ".backup.thirtyday.%N",
- "maxBackupVersions": 12
- }
- ],
- "columns": [
- {
- "name": "Name",
- "label": "Name",
- "can_set": true,
- "placeholder": "Example",
- "default": "Example"
- },
- {
- "name": "format",
- "label": "Rule Format",
- "can_set": true,
- "help": "Format used to create the extension for the backup of your persisted entities. Use a format with %N to get rolling. Or use date formatting like %Y-%m-%d.%H:%M:%S.%z",
- "placeholder": ".backup.example.%N",
- "default": ".backup.example.%N"
- },
- {
- "name": "backupInterval",
- "label": "Backup Interval in Seconds",
- "help": "Interval between backup checks in seconds.",
- "placeholder": 1800,
- "default": 1800,
- "can_set": true
- },
- {
- "name": "maxBackupVersions",
- "label": "Max Rolled Backup Versions",
- "help": "If your backup extension format uses 'rolling', how many versions do you want us to keep?",
- "placeholder": 5,
- "default": 5,
- "can_set": true
- }
- ]
- },
{
"name": "NoPersist",
"type": "checkbox",
@@ -1649,6 +1582,67 @@
}
]
},
+ {
+ "name": "automatic_content_archives",
+ "label": "Automatic Content Archives",
+ "settings": [
+ {
+ "name": "backup_rules",
+ "type": "table",
+ "label": "Rolling Backup Rules",
+ "help": "Define how frequently to create automatic content archives",
+ "numbered": false,
+ "can_add_new_rows": true,
+ "default": [
+ {
+ "Name": "Half Hourly Rolling",
+ "backupInterval": 1800,
+ "maxBackupVersions": 5
+ },
+ {
+ "Name": "Daily Rolling",
+ "backupInterval": 86400,
+ "maxBackupVersions": 7
+ },
+ {
+ "Name": "Weekly Rolling",
+ "backupInterval": 604800,
+ "maxBackupVersions": 4
+ },
+ {
+ "Name": "Thirty Day Rolling",
+ "backupInterval": 2592000,
+ "maxBackupVersions": 12
+ }
+ ],
+ "columns": [
+ {
+ "name": "Name",
+ "label": "Name",
+ "can_set": true,
+ "placeholder": "Example",
+ "default": "Example"
+ },
+ {
+ "name": "backupInterval",
+ "label": "Backup Interval in Seconds",
+ "help": "Interval between backup checks in seconds.",
+ "placeholder": 1800,
+ "default": 1800,
+ "can_set": true
+ },
+ {
+ "name": "maxBackupVersions",
+ "label": "Max Rolled Backup Versions",
+ "help": "If your backup extension format uses 'rolling', how many versions do you want us to keep?",
+ "placeholder": 5,
+ "default": 5,
+ "can_set": true
+ }
+ ]
+ }
+ ]
+ },
{
"name": "wizard",
"label": "Setup Wizard",
diff --git a/domain-server/resources/web/content/js/content.js b/domain-server/resources/web/content/js/content.js
index e2b653995f..0fd5f37a94 100644
--- a/domain-server/resources/web/content/js/content.js
+++ b/domain-server/resources/web/content/js/content.js
@@ -23,15 +23,17 @@ $(document).ready(function(){
var AUTOMATIC_ARCHIVES_TBODY_ID = 'automatic-archives-tbody';
var MANUAL_ARCHIVES_TABLE_ID = 'manual-archives-table';
var MANUAL_ARCHIVES_TBODY_ID = 'manual-archives-tbody';
+ var AUTO_ARCHIVES_SETTINGS_LINK_ID = 'auto-archives-settings-link';
+
var automaticBackups = [];
var manualBackups = [];
function setupContentArchives() {
-
// construct the HTML needed for the content archives panel
var html = "
";
html += "";
@@ -120,6 +122,30 @@ $(document).ready(function(){
});
}
+ // handle click on automatic content archive settings link
+ $('body').on('click', '#' + AUTO_ARCHIVES_SETTINGS_LINK_ID, function(e) {
+ if (Settings.pendingChanges > 0) {
+ // don't follow the link right away, make sure the user knows they are about to leave
+ // the page and lose changes
+ e.preventDefault();
+
+ var settingsLink = $(this).attr('href');
+
+ swal({
+ title: "Are you sure?",
+ text: "You have pending changes to content settings that have not been saved. They will be lost if you leave the page to manage automatic content archive intervals.",
+ type: "warning",
+ showCancelButton: true,
+ confirmButtonText: "Leave and Lose Pending Changes",
+ closeOnConfirm: true
+ },
+ function () {
+ // user wants to drop their changes, switch pages
+ window.location = settingsLink;
+ });
+ }
+ });
+
// handle click on manual archive creation button
$('body').on('click', '#' + GENERATE_ARCHIVE_BUTTON_ID, function(e) {
e.preventDefault();
diff --git a/domain-server/resources/web/js/base-settings.js b/domain-server/resources/web/js/base-settings.js
index 961a7df3b2..3476792222 100644
--- a/domain-server/resources/web/js/base-settings.js
+++ b/domain-server/resources/web/js/base-settings.js
@@ -126,6 +126,8 @@ function reloadSettings(callback) {
$('[data-toggle="tooltip"]').tooltip();
+ Settings.pendingChanges = 0;
+
// call the callback now that settings are loaded
callback(true);
}).fail(function() {
@@ -805,6 +807,8 @@ function badgeForDifferences(changedElement) {
}
});
+ Settings.pendingChanges = totalChanges;
+
if (totalChanges == 0) {
totalChanges = ""
}
diff --git a/domain-server/src/DomainContentBackupManager.cpp b/domain-server/src/DomainContentBackupManager.cpp
index a711d2112d..345faffec4 100644
--- a/domain-server/src/DomainContentBackupManager.cpp
+++ b/domain-server/src/DomainContentBackupManager.cpp
@@ -63,9 +63,9 @@ DomainContentBackupManager::DomainContentBackupManager(const QString& backupDire
}
void DomainContentBackupManager::parseSettings(const QJsonObject& settings) {
- qDebug() << settings << settings["backups"] << settings["backups"].isArray();
- if (settings["backups"].isArray()) {
- const QJsonArray& backupRules = settings["backups"].toArray();
+ static const QString BACKUP_RULES_KEY = "backup_rules";
+ if (settings[BACKUP_RULES_KEY].isArray()) {
+ const QJsonArray& backupRules = settings[BACKUP_RULES_KEY].toArray();
qCDebug(domain_server) << "BACKUP RULES:";
for (const QJsonValue& value : backupRules) {
diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp
index 157eaa483f..8247e12de5 100644
--- a/domain-server/src/DomainServer.cpp
+++ b/domain-server/src/DomainServer.cpp
@@ -296,8 +296,15 @@ DomainServer::DomainServer(int argc, char* argv[]) :
qCDebug(domain_server) << "Created entities data directory";
}
maybeHandleReplacementEntityFile();
+
+ auto contentArchivesGroup = _settingsManager.valueOrDefaultValueForKeyPath(AUTOMATIC_CONTENT_ARCHIVES_GROUP);
+ auto archivesIntervalObject = QJsonObject();
- _contentManager.reset(new DomainContentBackupManager(getContentBackupDir(), _settingsManager.settingsResponseObjectForType("6")["entity_server_settings"].toObject()));
+ if (contentArchivesGroup.canConvert()) {
+ archivesIntervalObject = QJsonObject::fromVariantMap(contentArchivesGroup.toMap());
+ }
+
+ _contentManager.reset(new DomainContentBackupManager(getContentBackupDir(), archivesIntervalObject));
connect(_contentManager.get(), &DomainContentBackupManager::started, _contentManager.get(), [this](){
_contentManager->addBackupHandler(BackupHandlerPointer(new EntitiesBackupHandler(getEntitiesFilePath(), getEntitiesReplacementFilePath())));
diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp
index 85d6a046b5..a50cde0807 100644
--- a/domain-server/src/DomainServerSettingsManager.cpp
+++ b/domain-server/src/DomainServerSettingsManager.cpp
@@ -393,6 +393,7 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
_standardAgentPermissions[NodePermissions::standardNameLocalhost]->set(NodePermissions::Permission::canRezTemporaryCertifiedEntities);
packPermissions();
}
+
if (oldVersion < 2.0) {
const QString WIZARD_COMPLETED_ONCE = "wizard.completed_once";
@@ -400,6 +401,7 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
*wizardCompletedOnce = QVariant(true);
}
+
if (oldVersion < 2.1) {
// convert old avatar scale settings into avatar height.
@@ -421,6 +423,21 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
}
}
+ if (oldVersion < 2.2) {
+ // migrate entity server rolling backup intervals to new location for automatic content archive intervals
+
+ const QString ENTITY_SERVER_BACKUPS_KEYPATH = "entity_server_settings.backups";
+ const QString AUTO_CONTENT_ARCHIVES_RULES_KEYPATH = "automatic_content_archives.backup_rules";
+
+ QVariant* previousBackupsVariant = _configMap.valueForKeyPath(ENTITY_SERVER_BACKUPS_KEYPATH);
+
+ if (previousBackupsVariant) {
+ auto migratedBackupsVariant = _configMap.valueForKeyPath(AUTO_CONTENT_ARCHIVES_RULES_KEYPATH, true);
+ *migratedBackupsVariant = *previousBackupsVariant;
+ }
+ }
+
+
// write the current description version to our settings
*versionVariant = _descriptionVersion;
diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h
index abc70751a8..897a15485f 100644
--- a/domain-server/src/DomainServerSettingsManager.h
+++ b/domain-server/src/DomainServerSettingsManager.h
@@ -37,6 +37,7 @@ const QString MAC_PERMISSIONS_KEYPATH = "security.mac_permissions";
const QString MACHINE_FINGERPRINT_PERMISSIONS_KEYPATH = "security.machine_fingerprint_permissions";
const QString GROUP_PERMISSIONS_KEYPATH = "security.group_permissions";
const QString GROUP_FORBIDDENS_KEYPATH = "security.group_forbiddens";
+const QString AUTOMATIC_CONTENT_ARCHIVES_GROUP = "automatic_content_archives";
using GroupByUUIDKey = QPair; // groupID, rankID