Skip to content

Commit ac8d435

Browse files
authored
[API] Implement App storage folder reset (#945)
* Split create_application_folders make separate functions for install_folder and storage_folder * Import enable_disable_functions for service stop and start * Implement app_data_manageable * Implement App data management to API Update api.py * Implement App data management to js * Implement data_manageable to template generic_app.html * app_data was reserved changed to data_folder which is used as variable on application_info.py * Implement reset_data functionality * simplify API of reset Implement simplification per requested at #945 (comment) * [FIX] Implement App data management on js * [FIX TYPOS] Update manage_apps.js * Revert "[FIX] Implement App data management on js" This reverts commit 9f01df1.
1 parent 017ebb0 commit ac8d435

File tree

4 files changed

+149
-6
lines changed

4 files changed

+149
-6
lines changed

rootfs/standard/var/pynode/application_info.py

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from drive_info import *
77
from systemctl_info import *
88
from utilities import *
9+
from enable_disable_functions import *
910
import copy
1011
import json
1112
import time
@@ -241,6 +242,7 @@ def initialize_application_defaults(app):
241242
if not "app_page_show_open_button" in app: app["app_page_show_open_button"] = True
242243
if not "app_page_additional_buttons" in app: app["app_page_additional_buttons"] = []
243244
if not "app_page_content" in app: app["app_page_content"] = []
245+
if not "data_manageable" in app: app["data_manageable"] = False
244246

245247
# Update fields that may use variables that need replacing, like {VERSION}, {SHORT_NAME}, etc...
246248
app["download_source_url"] = replace_app_info_variables(app, app["download_source_url"])
@@ -633,25 +635,39 @@ def create_application_user(app_data):
633635
if app_data["requires_docker_image_installation"]:
634636
add_user_to_group(username, "docker")
635637

636-
def create_application_folders(app_data):
637-
log_message(" Running create_application_folders...")
638+
def create_application_install_folder(app_data):
639+
log_message(" Running create_application_install_folder...")
638640
app_folder = app_data["install_folder"]
639-
data_folder = app_data["storage_folder"]
640641

641642
# Clear old data (not storage)
642643
if os.path.isdir(app_folder):
643644
log_message(" App folder exists, deleting...")
644645
run_linux_cmd("rm -rf {}".format(app_folder))
645646

646-
log_message(" Making application folders...")
647+
log_message(" Making application install folder...")
647648
run_linux_cmd("mkdir {}".format(app_folder))
648-
run_linux_cmd("mkdir -p {}".format(data_folder))
649649

650650
# Set folder permissions (always set for now - could check to see if already proper user)
651-
log_message(" Updating folder permissions...")
651+
log_message(" Updating install folder permissions...")
652652
run_linux_cmd("chown -R {}:{} {}".format(app_data["linux_user"], app_data["linux_user"], app_folder))
653+
654+
def create_application_storage_folder(app_data):
655+
log_message(" Running create_application_storage_folder...")
656+
data_folder = app_data["storage_folder"]
657+
658+
log_message(" Making application storage_folder...")
659+
run_linux_cmd("mkdir -p {}".format(data_folder))
660+
661+
# Set folder permissions (always set for now - could check to see if already proper user)
662+
log_message(" Updating storage folder permissions...")
653663
run_linux_cmd("chown -R {}:{} {}".format(app_data["linux_user"], app_data["linux_user"], data_folder))
654664

665+
def create_application_folders(app_data):
666+
log_message(" Running create_application_folders...")
667+
668+
create_application_install_folder(app_data)
669+
create_application_storage_folder(app_data)
670+
655671
def create_application_tor_service(app_data):
656672
has_ports = False
657673
run_linux_cmd("mkdir -p /etc/torrc.d")
@@ -738,6 +754,39 @@ def restart_application(short_name):
738754
except Exception as e:
739755
return False
740756

757+
def backup_data_folder(app_data):
758+
log_message(" Running backup_data_folder...")
759+
760+
def restore_data_folder(app_data):
761+
log_message(" Running restore_data_folder...")
762+
763+
def reset_data_folder(short_name):
764+
log_message(f" Running reset_data_folder for '{short_name}'...")
765+
766+
app_data = get_application(short_name)
767+
if not app_data:
768+
log_message(f" ERROR: application '{short_name}' not found")
769+
return False
770+
data_folder = app_data["storage_folder"]
771+
772+
# Stop the service before removing data_folder
773+
log_message(f" Stopping '{short_name}'…")
774+
stop_service(short_name)
775+
776+
# Remove App data_folder
777+
log_message(f" Removing storage folder '{data_folder}'…")
778+
run_linux_cmd(f"rm -rf {data_folder}")
779+
780+
# Re-create the storage folder
781+
log_message(f" Creating storage folder '{data_folder}'…")
782+
create_application_storage_folder(app_data)
783+
784+
# Re-start the service
785+
log_message(f" Starting '{short_name}'…")
786+
start_service(short_name)
787+
788+
return True
789+
741790
######################################################################################
742791
## Bulk Application Actions
743792
######################################################################################

rootfs/standard/var/www/mynode/api.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,45 @@ def api_restart_app():
149149

150150
return "OK"
151151

152+
@mynode_api.route("/api/backup_data_folder")
153+
def api_backup_data_folder():
154+
check_logged_in()
155+
156+
short_name = request.args.get("short_name")
157+
if not short_name:
158+
return "NO_APP_SPECIFIED"
159+
if not is_application_valid(short_name):
160+
return "INVALID_APP_NAME"
161+
if not backup_data_folder(short_name):
162+
return "ERROR"
163+
return "OK"
164+
165+
@mynode_api.route("/api/restore_data_folder")
166+
def api_restore_data_folder():
167+
check_logged_in()
168+
169+
short_name = request.args.get("short_name")
170+
if not short_name:
171+
return "NO_APP_SPECIFIED"
172+
if not is_application_valid(short_name):
173+
return "INVALID_APP_NAME"
174+
if not restore_data_folder(short_name):
175+
return "ERROR"
176+
return "OK"
177+
178+
@mynode_api.route("/api/reset_data_folder")
179+
def api_reset_data_folder():
180+
check_logged_in()
181+
182+
short_name = request.args.get("short_name")
183+
if not short_name:
184+
return "NO_APP_SPECIFIED"
185+
if not is_application_valid(short_name):
186+
return "INVALID_APP_NAME"
187+
if not reset_data_folder(short_name):
188+
return "ERROR"
189+
return "OK"
190+
152191
@mynode_api.route("/api/get_device_info")
153192
def api_get_device_info():
154193
check_logged_in()

rootfs/standard/var/www/mynode/static/js/manage_apps.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,53 @@ function toggleEnabled(short_name, full_name, enable, return_page="") {
127127
window.location.href="/toggle-enabled?app="+short_name+r
128128
});
129129
}
130+
}
131+
132+
// ==========================================
133+
// Manage app storage (data_folder)
134+
// ==========================================
135+
136+
function backup_data_folder_via_api(name, short_name) {
137+
if ( confirm("Are you sure you want to backup "+name+"? This will stop, backup data and start app.") ) {
138+
$('#loading_spinner_message').html("Making backup...");
139+
$('#loading_spinner_overlay').fadeIn();
140+
$.get('/api/backup_data_folder?app='+short_name)
141+
.done(function( data ) {
142+
if (data != "OK") {
143+
alert("Error backing up app data: "+data)
144+
}
145+
$('#loading_spinner_overlay').fadeOut();
146+
}
147+
);
148+
}
149+
}
150+
151+
function restore_data_folder_via_api(name, short_name) {
152+
if ( confirm("Are you sure you want to restore "+name+"? This will stop, DELETE DATA, restore backup and start app.") ) {
153+
$('#loading_spinner_message').html("Restoring...");
154+
$('#loading_spinner_overlay').fadeIn();
155+
$.get('/api/restore_data_folder?app='+short_name)
156+
.done(function( data ) {
157+
if (data != "OK") {
158+
alert("Error restoring app data: "+data)
159+
}
160+
$('#loading_spinner_overlay').fadeOut();
161+
}
162+
);
163+
}
164+
}
165+
166+
function reset_data_folder_via_api(name, short_name) {
167+
if ( confirm("Are you sure you want to reset "+name+"? This will stop app, RESET ALL THE APP DATA and start app.") ) {
168+
$('#loading_spinner_message').html("Resetting app...");
169+
$('#loading_spinner_overlay').fadeIn();
170+
$.get('/api/reset_data_folder?app='+short_name)
171+
.done(function( data ) {
172+
if (data != "OK") {
173+
alert("Error removing app data: "+data)
174+
}
175+
$('#loading_spinner_overlay').fadeOut();
176+
}
177+
);
178+
}
130179
}

rootfs/standard/var/www/mynode/templates/app/generic_app.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@
8282
{% if app.is_enabled %}
8383
<button class="ui-button ui-widget ui-corner-all mynode_button app_page_button" onclick="restart_app_via_api('{{ app.name }}', '{{ app.short_name }}');">Restart</button>
8484

85+
{% if app.is_enabled and app.data_manageable %}
86+
<!-- <button class="ui-button ui-widget ui-corner-all mynode_button app_page_button" onclick="backup_data_folder_via_api('{{ app.name }}', '{{ app.short_name }}');">Backup Data</button>
87+
<button class="ui-button ui-widget ui-corner-all mynode_button app_page_button" onclick="restore_data_folder_via_api('{{ app.name }}', '{{ app.short_name }}');">Restore Data</button>
88+
--> <button class="ui-button ui-widget ui-corner-all mynode_button app_page_button" onclick="reset_data_folder_via_api('{{ app.name }}', '{{ app.short_name }}');">Reset Data</button>
89+
{% endif %}
90+
8591
{% for btn in app.app_page_additional_buttons %}
8692
<button class="ui-button ui-widget ui-corner-all mynode_button app_page_button"
8793
{% if btn.href is defined and btn.href != "" %}

0 commit comments

Comments
 (0)