From 2aa0dbd93d6c35af6665001728b012333ebda3b0 Mon Sep 17 00:00:00 2001 From: Safihre Date: Sun, 4 Jul 2021 18:03:42 +0300 Subject: [PATCH] Transfer /status/ functions to API-functions TODO: Update documentation and maybe some tests --- interfaces/Glitter/templates/include_overlays.tmpl | 14 +- .../templates/static/javascripts/glitter.main.js | 55 ++- interfaces/Glitter/templates/status.tmpl | 1 - sabnzbd/__init__.py | 1 - sabnzbd/api.py | 130 +++++- sabnzbd/interface.py | 435 +++++++-------------- tests/test_functional_misc.py | 2 +- 7 files changed, 309 insertions(+), 329 deletions(-) delete mode 100644 interfaces/Glitter/templates/status.tmpl diff --git a/interfaces/Glitter/templates/include_overlays.tmpl b/interfaces/Glitter/templates/include_overlays.tmpl index a367b0f..0faea5b 100644 --- a/interfaces/Glitter/templates/include_overlays.tmpl +++ b/interfaces/Glitter/templates/include_overlays.tmpl @@ -116,7 +116,7 @@
$T('dashboard-systemPerformance')  
- +
$T('Glitter-loading')...
@@ -125,7 +125,7 @@
$T('dashboard-downloadDirSpeed')  
MB/s - + ()
$T('Glitter-loading')...
@@ -134,7 +134,7 @@
$T('dashboard-completeDirSpeed')  
MB/s - + ()
$T('Glitter-loading')...
@@ -143,7 +143,7 @@
$T('dashboard-internetBandwidth')  
MB/s - + ( Mbps)
$T('Glitter-loading')...
@@ -170,7 +170,7 @@
@@ -285,8 +285,8 @@ - - + + diff --git a/interfaces/Glitter/templates/static/javascripts/glitter.main.js b/interfaces/Glitter/templates/static/javascripts/glitter.main.js index dfc2978..d3225ea 100644 --- a/interfaces/Glitter/templates/static/javascripts/glitter.main.js +++ b/interfaces/Glitter/templates/static/javascripts/glitter.main.js @@ -739,14 +739,26 @@ function ViewModel() { // Full refresh? Only on click and for the status-screen var statusFullRefresh = (event != undefined) && $('#options-status').hasClass('active'); + // Measure performance? Takes a while + var statusPerformance = (event != undefined) && $(event.currentTarget).hasClass('diskspeed-button'); + // Make it spin if the user requested it otherwise we don't, // because browsers use a lot of CPU for the animation if(statusFullRefresh) { self.hasStatusInfo(false) } + // Show loading text for performance measures + if(statusPerformance) { + self.hasPerformanceInfo(false) + } + // Load the custom status info - callAPI({ mode: 'fullstatus', skip_dashboard: (!statusFullRefresh)*1 }).then(function(data) { + callAPI({ + mode: 'status', + calculate_performance: statusPerformance*1, + skip_dashboard: (!statusFullRefresh)*1 + }).then(function(data) { // Update basic self.statusInfo.loglevel(data.status.loglevel) self.statusInfo.folders(data.status.folders) @@ -774,8 +786,11 @@ function ViewModel() { if(self.statusInfo.servers().length == 0) { self.statusInfo.loglevel.subscribe(function(newValue) { // Update log-level - callSpecialAPI('./status/change_loglevel/', { - loglevel: newValue + callAPI({ + mode: "set_config", + section: "logging", + keyword: "log_level", + value: newValue }); }) } @@ -825,16 +840,6 @@ function ViewModel() { }); } - // Do a disk-speedtest - self.testDiskSpeed = function(item, event) { - self.hasPerformanceInfo(false) - - // Run it and then display it - callSpecialAPI('./status/dashrefresh/').then(function() { - self.loadStatusInfo(true, true) - }) - } - // Download a test-NZB self.testDownload = function(data, event) { var nzbSize = $(event.target).data('size') @@ -861,8 +866,10 @@ function ViewModel() { // Unblock server self.unblockServer = function(servername) { - callSpecialAPI("./status/unblock_server/", { - server: servername + callAPI({ + mode: "status", + name: "unblock_server", + value: servername }).then(function() { $("#modal-options").modal("hide"); }) @@ -920,7 +927,7 @@ function ViewModel() { $('#options-orphans [data-tooltip="true"]').tooltip('hide') // Show notification on delete - if($(htmlElement.currentTarget).data('action') == 'delete') { + if($(htmlElement.currentTarget).data('action') == 'delete_orphan') { showNotification('.main-notification-box-removing', 1000) } else { // Adding back to queue @@ -928,8 +935,10 @@ function ViewModel() { } // Activate - callSpecialAPI("./status/" + $(htmlElement.currentTarget).data('action'), { - name: $("
").html(folder).text() + callAPI({ + mode: "status", + name: $(htmlElement.currentTarget).data('action'), + value: $("
").html(folder).text() }).then(function() { // Refresh self.loadStatusInfo(true, true) @@ -944,7 +953,10 @@ function ViewModel() { // Show notification showNotification('.main-notification-box-removing-multiple', 0, self.statusInfo.folders().length) // Delete them all - callSpecialAPI("./status/delete_all/").then(function() { + callAPI({ + mode: "status", + name: "delete_all_orphan" + }).then(function() { // Remove notifcation and update screen hideNotification() self.loadStatusInfo(true, true) @@ -958,7 +970,10 @@ function ViewModel() { // Show notification showNotification('.main-notification-box-sendback') // Delete them all - callSpecialAPI("./status/add_all/").then(function() { + callAPI({ + mode: "status", + name: "add_all_orphan" + }).then(function() { // Remove notifcation and update screen hideNotification() self.loadStatusInfo(true, true) diff --git a/interfaces/Glitter/templates/status.tmpl b/interfaces/Glitter/templates/status.tmpl deleted file mode 100644 index 149cf6d..0000000 --- a/interfaces/Glitter/templates/status.tmpl +++ /dev/null @@ -1 +0,0 @@ -   \ No newline at end of file diff --git a/sabnzbd/__init__.py b/sabnzbd/__init__.py index 823c3ab..9234d44 100644 --- a/sabnzbd/__init__.py +++ b/sabnzbd/__init__.py @@ -164,7 +164,6 @@ LINUX_POWER = powersup.HAVE_DBUS LOGFILE = None WEBLOGFILE = None -LOGHANDLER = None GUIHANDLER = None LOG_ALL = False AMBI_LOCALHOST = False diff --git a/sabnzbd/api.py b/sabnzbd/api.py index af869f1..1abb1d7 100644 --- a/sabnzbd/api.py +++ b/sabnzbd/api.py @@ -26,6 +26,7 @@ import gc import datetime import time import json +import getpass import cherrypy from threading import Thread from typing import Tuple, Optional, List, Dict, Any @@ -45,8 +46,10 @@ from sabnzbd.constants import ( import sabnzbd.config as config import sabnzbd.cfg as cfg from sabnzbd.skintext import SKIN_TEXT +from sabnzbd.utils.diskspeed import diskspeedmeasure +from sabnzbd.utils.internetspeed import internetspeed from sabnzbd.utils.pathbrowser import folders_at_path -from sabnzbd.utils.getperformance import getcpu +from sabnzbd.utils.getperformance import getcpu, getpystone from sabnzbd.misc import ( loadavg, to_units, @@ -459,10 +462,62 @@ def _api_change_opts(name, kwargs): def _api_fullstatus(name, kwargs): """API: full history status""" - status = build_status(skip_dashboard=kwargs.get("skip_dashboard", 1)) + status = build_status( + calculate_performance=kwargs.get("calculate_performance", 0), skip_dashboard=kwargs.get("skip_dashboard", 1) + ) return report(keyword="status", data=status) +def _api_status(name, kwargs): + """API: Dispatcher for mode=status, passing on the value""" + value = kwargs.get("value", "") + return _api_status_table.get(name, (_api_fullstatus, 2))[0](value, kwargs) + + +def _api_unblock_server(value, kwargs): + """Unblock a blocked server""" + sabnzbd.Downloader.unblock(value) + return report() + + +def _api_delete_orphan(path, kwargs): + """Remove orphaned job""" + if path: + path = os.path.join(cfg.download_dir.get_path(), path) + logging.info("Removing orphaned job %s", path) + remove_all(path, recursive=True) + return report() + else: + return report(_MSG_NO_ITEM) + + +def _api_delete_all_orphan(value, kwargs): + """Remove all orphaned jobs""" + paths = sabnzbd.NzbQueue.scan_jobs(all_jobs=False, action=False) + for path in paths: + _api_delete_orphan(path, kwargs) + return report() + + +def _api_add_orphan(path, kwargs): + """Add orphaned job""" + if path: + path = os.path.join(cfg.download_dir.get_path(), path) + logging.info("Re-adding orphaned job %s", path) + sabnzbd.NzbQueue.repair_job(path, None, None) + return report() + else: + return report(_MSG_NO_ITEM) + + +def _api_add_all_orphan(value, kwargs): + """Add all orphaned jobs""" + paths = sabnzbd.NzbQueue.scan_jobs(all_jobs=False, action=False) + for path in paths: + _api_add_orphan(path, kwargs) + return report() + + def _api_history(name, kwargs): """API: accepts value(=nzo_id), start, limit, search, nzo_ids""" value = kwargs.get("value", "") @@ -615,6 +670,51 @@ def _api_warnings(name, kwargs): return report(keyword="warnings", data=sabnzbd.GUIHANDLER.content()) +LOG_API_RE = re.compile(rb"(apikey|api)([=:])[\w]+", re.I) +LOG_API_JSON_RE = re.compile(rb"'(apikey|api)': '[\w]+'", re.I) +LOG_USER_RE = re.compile(rb"(user|username)\s?=\s?[\S]+", re.I) +LOG_PASS_RE = re.compile(rb"(password)\s?=\s?[\S]+", re.I) +LOG_INI_HIDE_RE = re.compile( + rb"(email_pwd|email_account|email_to|rating_api_key|pushover_token|pushover_userkey|pushbullet_apikey|prowl_apikey|growl_password|growl_server|IPv[4|6] address)\s?=\s?[\S]+", + re.I, +) +LOG_HASH_RE = re.compile(rb"([a-fA-F\d]{25})", re.I) + + +def _api_showlog(name, kwargs): + """Fetch the INI and the log-data and add a message at the top""" + log_data = b"--------------------------------\n\n" + log_data += b"The log includes a copy of your sabnzbd.ini with\nall usernames, passwords and API-keys removed." + log_data += b"\n\n--------------------------------\n" + + with open(sabnzbd.LOGFILE, "rb") as f: + log_data += f.read() + + with open(config.get_filename(), "rb") as f: + log_data += f.read() + + # We need to remove all passwords/usernames/api-keys + log_data = LOG_API_RE.sub(b"apikey=", log_data) + log_data = LOG_API_JSON_RE.sub(b"'apikey':'", log_data) + log_data = LOG_USER_RE.sub(b"\\g<1>=", log_data) + log_data = LOG_PASS_RE.sub(b"password=", log_data) + log_data = LOG_INI_HIDE_RE.sub(b"\\1 = ", log_data) + log_data = LOG_HASH_RE.sub(b"", log_data) + + # Try to replace the username + try: + cur_user = getpass.getuser() + if cur_user: + log_data = log_data.replace(utob(cur_user), b"") + except: + pass + + # Set headers + cherrypy.response.headers["Content-Type"] = "application/x-download;charset=utf-8" + cherrypy.response.headers["Content-Disposition"] = 'attachment;filename="sabnzbd.log"' + return log_data + + def _api_get_cats(name, kwargs): return report(keyword="categories", data=list_cats(False)) @@ -933,6 +1033,7 @@ _api_table = { "change_script": (_api_change_script, 2), "change_opts": (_api_change_opts, 2), "fullstatus": (_api_fullstatus, 2), + "status": (_api_status, 2), "history": (_api_history, 2), "get_files": (_api_get_files, 2), "move_nzf_bulk": (_api_move_nzf_bulk, 2), @@ -942,6 +1043,7 @@ _api_table = { "resume": (_api_resume, 2), "shutdown": (_api_shutdown, 3), "warnings": (_api_warnings, 2), + "showlog": (_api_showlog, 3), "config": (_api_config, 2), "get_cats": (_api_get_cats, 2), "get_scripts": (_api_get_scripts, 2), @@ -984,6 +1086,14 @@ _api_queue_table = { "rating": (_api_queue_rating, 2), } +_api_status_table = { + "unblock_server": (_api_unblock_server, 2), + "delete_orphan": (_api_delete_orphan, 2), + "delete_all_orphan": (_api_delete_all_orphan, 2), + "add_orphan": (_api_add_orphan, 2), + "add_all_orphan": (_api_add_all_orphan, 2), +} + _api_config_table = { "speedlimit": (_api_config_speedlimit, 2), "set_speedlimit": (_api_config_speedlimit, 2), @@ -1001,6 +1111,8 @@ def api_level(mode: str, name: str) -> int: """Return access level required for this API call""" if mode == "queue" and name in _api_queue_table: return _api_queue_table[name][1] + if mode == "status" and name in _api_status_table: + return _api_status_table[name][1] if mode == "config" and name in _api_config_table: return _api_config_table[name][1] if mode in _api_table: @@ -1184,7 +1296,7 @@ def handle_cat_api(kwargs): return name -def build_status(skip_dashboard: bool = False) -> Dict[str, Any]: +def build_status(calculate_performance: bool = False, skip_dashboard: bool = False) -> Dict[str, Any]: # build up header full of basic information info = build_header(trans_functions=False) @@ -1195,6 +1307,18 @@ def build_status(skip_dashboard: bool = False) -> Dict[str, Any]: info["configfn"] = config.get_filename() info["warnings"] = sabnzbd.GUIHANDLER.content() + # Calculate performance measures, if requested + if int_conv(calculate_performance): + # PyStone + sabnzbd.PYSTONE_SCORE = getpystone() + + # Diskspeed of download (aka incomplete) and complete directory: + sabnzbd.DOWNLOAD_DIR_SPEED = round(diskspeedmeasure(sabnzbd.cfg.download_dir.get_path()), 1) + sabnzbd.COMPLETE_DIR_SPEED = round(diskspeedmeasure(sabnzbd.cfg.complete_dir.get_path()), 1) + + # Internet bandwidth + sabnzbd.INTERNET_BANDWIDTH = round(internetspeed(), 1) + # Dashboard: Speed of System info["cpumodel"] = getcpu() info["pystone"] = sabnzbd.PYSTONE_SCORE diff --git a/sabnzbd/interface.py b/sabnzbd/interface.py index f7a8c88..09c84e3 100644 --- a/sabnzbd/interface.py +++ b/sabnzbd/interface.py @@ -54,10 +54,8 @@ from sabnzbd.misc import ( ) from sabnzbd.filesystem import ( real_path, - long_path, globber, globber_full, - remove_all, clip_path, same_file, setname_from_path, @@ -68,9 +66,6 @@ import sabnzbd.cfg as cfg import sabnzbd.notifier as notifier import sabnzbd.newsunpack from sabnzbd.utils.servertests import test_nntp_server_dict -from sabnzbd.utils.diskspeed import diskspeedmeasure -from sabnzbd.utils.getperformance import getpystone -from sabnzbd.utils.internetspeed import internetspeed import sabnzbd.utils.ssdp from sabnzbd.constants import DEF_STDCONFIG, DEFAULT_PRIORITY, CHEETAH_DIRECTIVES, EXCLUDED_GUESSIT_PROPERTIES from sabnzbd.lang import list_languages @@ -194,7 +189,6 @@ def check_access(access_type: int = 4, warn_user: bool = False) -> bool: if is_loopback_addr(remote_ip): return True - is_allowed = False if not cfg.local_ranges(): # No local ranges defined, allow all private addresses by default is_allowed = is_lan_addr(remote_ip) @@ -409,7 +403,6 @@ class MainPage: # Add all sub-pages self.login = LoginPage() - self.status = Status("/status/") self.config = ConfigPage("/config/") self.wizard = Wizard("/wizard/") @@ -419,11 +412,6 @@ class MainPage: if kwargs.get("skip_wizard") or config.get_servers(): info = build_header() - info["scripts"] = list_scripts(default=True) - info["script"] = "Default" - - info["cat"] = "Default" - info["categories"] = list_cats(True) info["have_rss_defined"] = bool(config.get_rss()) info["have_watched_dir"] = bool(cfg.dirscan_dir()) @@ -1429,10 +1417,10 @@ class ConfigRss: uri = Strip(kwargs.get("uri")) if feed and uri: try: - cfg = config.get_rss()[feed] + rss_cfg = config.get_rss()[feed] except KeyError: - cfg = None - if (not cfg) and uri: + rss_cfg = None + if not rss_cfg and uri: kwargs["feed"] = feed kwargs["uri"] = uri config.ConfigRSS(feed, kwargs) @@ -1923,152 +1911,6 @@ class ConfigSorting: raise Raiser(self.__root) -############################################################################## -LOG_API_RE = re.compile(rb"(apikey|api)(=|:)[\w]+", re.I) -LOG_API_JSON_RE = re.compile(rb"'(apikey|api)': '[\w]+'", re.I) -LOG_USER_RE = re.compile(rb"(user|username)\s?=\s?[\S]+", re.I) -LOG_PASS_RE = re.compile(rb"(password)\s?=\s?[\S]+", re.I) -LOG_INI_HIDE_RE = re.compile( - rb"(email_pwd|email_account|email_to|rating_api_key|pushover_token|pushover_userkey|pushbullet_apikey|prowl_apikey|growl_password|growl_server|IPv[4|6] address)\s?=\s?[\S]+", - re.I, -) -LOG_HASH_RE = re.compile(rb"([a-fA-F\d]{25})", re.I) - - -class Status: - def __init__(self, root): - self.__root = root - - @secured_expose(check_configlock=True) - def index(self, **kwargs): - template = Template(file=os.path.join(sabnzbd.WEB_DIR, "status.tmpl"), compilerSettings=CHEETAH_DIRECTIVES) - return template.respond() - - @secured_expose(check_api_key=True) - def showlog(self, **kwargs): - try: - sabnzbd.LOGHANDLER.flush() - except: - pass - - # Fetch the INI and the log-data and add a message at the top - log_data = b"--------------------------------\n\n" - log_data += b"The log includes a copy of your sabnzbd.ini with\nall usernames, passwords and API-keys removed." - log_data += b"\n\n--------------------------------\n" - - with open(sabnzbd.LOGFILE, "rb") as f: - log_data += f.read() - - with open(config.get_filename(), "rb") as f: - log_data += f.read() - - # We need to remove all passwords/usernames/api-keys - log_data = LOG_API_RE.sub(b"apikey=", log_data) - log_data = LOG_API_JSON_RE.sub(b"'apikey':'", log_data) - log_data = LOG_USER_RE.sub(b"\\g<1>=", log_data) - log_data = LOG_PASS_RE.sub(b"password=", log_data) - log_data = LOG_INI_HIDE_RE.sub(b"\\1 = ", log_data) - log_data = LOG_HASH_RE.sub(b"", log_data) - - # Try to replace the username - try: - import getpass - - cur_user = getpass.getuser() - if cur_user: - log_data = log_data.replace(utob(cur_user), b"") - except: - pass - # Set headers - cherrypy.response.headers["Content-Type"] = "application/x-download;charset=utf-8" - cherrypy.response.headers["Content-Disposition"] = 'attachment;filename="sabnzbd.log"' - return log_data - - @secured_expose(check_api_key=True) - def change_loglevel(self, **kwargs): - cfg.log_level.set(kwargs.get("loglevel")) - config.save_config() - - raise Raiser(self.__root) - - @secured_expose(check_api_key=True) - def unblock_server(self, **kwargs): - sabnzbd.Downloader.unblock(kwargs.get("server")) - # Short sleep so that UI shows new server status - time.sleep(1.0) - raise Raiser(self.__root) - - @secured_expose(check_api_key=True) - def delete(self, **kwargs): - orphan_delete(kwargs) - raise Raiser(self.__root) - - @secured_expose(check_api_key=True) - def delete_all(self, **kwargs): - paths = sabnzbd.NzbQueue.scan_jobs(all_jobs=False, action=False) - for path in paths: - kwargs = {"name": path} - orphan_delete(kwargs) - raise Raiser(self.__root) - - @secured_expose(check_api_key=True) - def add(self, **kwargs): - orphan_add(kwargs) - raise Raiser(self.__root) - - @secured_expose(check_api_key=True) - def add_all(self, **kwargs): - paths = sabnzbd.NzbQueue.scan_jobs(all_jobs=False, action=False) - for path in paths: - kwargs = {"name": path} - orphan_add(kwargs) - raise Raiser(self.__root) - - @secured_expose(check_api_key=True) - def dashrefresh(self, **kwargs): - # This function is run when Refresh button on Dashboard is clicked - # Put the time consuming dashboard functions here; they only get executed when the user clicks the Refresh button - - # PyStone - sabnzbd.PYSTONE_SCORE = getpystone() - - # Diskspeed of download (aka incomplete) directory: - dir_speed = diskspeedmeasure(sabnzbd.cfg.download_dir.get_path()) - if dir_speed: - sabnzbd.DOWNLOAD_DIR_SPEED = round(dir_speed, 1) - else: - sabnzbd.DOWNLOAD_DIR_SPEED = 0 - - time.sleep(1.0) - # Diskspeed of complete directory: - dir_speed = diskspeedmeasure(sabnzbd.cfg.complete_dir.get_path()) - if dir_speed: - sabnzbd.COMPLETE_DIR_SPEED = round(dir_speed, 1) - else: - sabnzbd.COMPLETE_DIR_SPEED = 0 - - # Internet bandwidth - sabnzbd.INTERNET_BANDWIDTH = round(internetspeed(), 1) - - raise Raiser(self.__root) # Refresh screen - - -def orphan_delete(kwargs): - path = kwargs.get("name") - if path: - path = os.path.join(long_path(cfg.download_dir.get_path()), path) - logging.info("Removing orphaned job %s", path) - remove_all(path, recursive=True) - - -def orphan_add(kwargs): - path = kwargs.get("name") - if path: - path = os.path.join(long_path(cfg.download_dir.get_path()), path) - logging.info("Re-adding orphaned job %s", path) - sabnzbd.NzbQueue.repair_job(path, None, None) - - def badParameterResponse(msg, ajax=None): """Return a html page with error message and a 'back' button""" if ajax: @@ -2187,141 +2029,142 @@ def GetRssLog(feed): ############################################################################## -NOTIFY_OPTIONS = {} -NOTIFY_OPTIONS["misc"] = ( - "email_endjob", - "email_cats", - "email_full", - "email_server", - "email_to", - "email_from", - "email_account", - "email_pwd", - "email_rss", -) -NOTIFY_OPTIONS["ncenter"] = ( - "ncenter_enable", - "ncenter_cats", - "ncenter_prio_startup", - "ncenter_prio_download", - "ncenter_prio_pause_resume", - "ncenter_prio_pp", - "ncenter_prio_pp", - "ncenter_prio_complete", - "ncenter_prio_failed", - "ncenter_prio_disk_full", - "ncenter_prio_warning", - "ncenter_prio_error", - "ncenter_prio_queue_done", - "ncenter_prio_other", - "ncenter_prio_new_login", -) -NOTIFY_OPTIONS["acenter"] = ( - "acenter_enable", - "acenter_cats", - "acenter_prio_startup", - "acenter_prio_download", - "acenter_prio_pause_resume", - "acenter_prio_pp", - "acenter_prio_complete", - "acenter_prio_failed", - "acenter_prio_disk_full", - "acenter_prio_warning", - "acenter_prio_error", - "acenter_prio_queue_done", - "acenter_prio_other", - "acenter_prio_new_login", -) -NOTIFY_OPTIONS["ntfosd"] = ( - "ntfosd_enable", - "ntfosd_cats", - "ntfosd_prio_startup", - "ntfosd_prio_download", - "ntfosd_prio_pause_resume", - "ntfosd_prio_pp", - "ntfosd_prio_complete", - "ntfosd_prio_failed", - "ntfosd_prio_disk_full", - "ntfosd_prio_warning", - "ntfosd_prio_error", - "ntfosd_prio_queue_done", - "ntfosd_prio_other", - "ntfosd_prio_new_login", -) -NOTIFY_OPTIONS["prowl"] = ( - "prowl_enable", - "prowl_cats", - "prowl_apikey", - "prowl_prio_startup", - "prowl_prio_download", - "prowl_prio_pause_resume", - "prowl_prio_pp", - "prowl_prio_complete", - "prowl_prio_failed", - "prowl_prio_disk_full", - "prowl_prio_warning", - "prowl_prio_error", - "prowl_prio_queue_done", - "prowl_prio_other", - "prowl_prio_new_login", -) -NOTIFY_OPTIONS["pushover"] = ( - "pushover_enable", - "pushover_cats", - "pushover_token", - "pushover_userkey", - "pushover_device", - "pushover_prio_startup", - "pushover_prio_download", - "pushover_prio_pause_resume", - "pushover_prio_pp", - "pushover_prio_complete", - "pushover_prio_failed", - "pushover_prio_disk_full", - "pushover_prio_warning", - "pushover_prio_error", - "pushover_prio_queue_done", - "pushover_prio_other", - "pushover_prio_new_login", - "pushover_emergency_retry", - "pushover_emergency_expire", -) -NOTIFY_OPTIONS["pushbullet"] = ( - "pushbullet_enable", - "pushbullet_cats", - "pushbullet_apikey", - "pushbullet_device", - "pushbullet_prio_startup", - "pushbullet_prio_download", - "pushbullet_prio_pause_resume", - "pushbullet_prio_pp", - "pushbullet_prio_complete", - "pushbullet_prio_failed", - "pushbullet_prio_disk_full", - "pushbullet_prio_warning", - "pushbullet_prio_error", - "pushbullet_prio_queue_done", - "pushbullet_prio_other", - "pushbullet_prio_new_login", -) -NOTIFY_OPTIONS["nscript"] = ( - "nscript_enable", - "nscript_cats", - "nscript_script", - "nscript_parameters", - "nscript_prio_startup", - "nscript_prio_download", - "nscript_prio_pause_resume", - "nscript_prio_pp", - "nscript_prio_complete", - "nscript_prio_failed", - "nscript_prio_disk_full", - "nscript_prio_warning", - "nscript_prio_error", - "nscript_prio_queue_done", - "nscript_prio_other", - "nscript_prio_new_login", -) +NOTIFY_OPTIONS = { + "misc": ( + "email_endjob", + "email_cats", + "email_full", + "email_server", + "email_to", + "email_from", + "email_account", + "email_pwd", + "email_rss", + ), + "ncenter": ( + "ncenter_enable", + "ncenter_cats", + "ncenter_prio_startup", + "ncenter_prio_download", + "ncenter_prio_pause_resume", + "ncenter_prio_pp", + "ncenter_prio_pp", + "ncenter_prio_complete", + "ncenter_prio_failed", + "ncenter_prio_disk_full", + "ncenter_prio_warning", + "ncenter_prio_error", + "ncenter_prio_queue_done", + "ncenter_prio_other", + "ncenter_prio_new_login", + ), + "acenter": ( + "acenter_enable", + "acenter_cats", + "acenter_prio_startup", + "acenter_prio_download", + "acenter_prio_pause_resume", + "acenter_prio_pp", + "acenter_prio_complete", + "acenter_prio_failed", + "acenter_prio_disk_full", + "acenter_prio_warning", + "acenter_prio_error", + "acenter_prio_queue_done", + "acenter_prio_other", + "acenter_prio_new_login", + ), + "ntfosd": ( + "ntfosd_enable", + "ntfosd_cats", + "ntfosd_prio_startup", + "ntfosd_prio_download", + "ntfosd_prio_pause_resume", + "ntfosd_prio_pp", + "ntfosd_prio_complete", + "ntfosd_prio_failed", + "ntfosd_prio_disk_full", + "ntfosd_prio_warning", + "ntfosd_prio_error", + "ntfosd_prio_queue_done", + "ntfosd_prio_other", + "ntfosd_prio_new_login", + ), + "prowl": ( + "prowl_enable", + "prowl_cats", + "prowl_apikey", + "prowl_prio_startup", + "prowl_prio_download", + "prowl_prio_pause_resume", + "prowl_prio_pp", + "prowl_prio_complete", + "prowl_prio_failed", + "prowl_prio_disk_full", + "prowl_prio_warning", + "prowl_prio_error", + "prowl_prio_queue_done", + "prowl_prio_other", + "prowl_prio_new_login", + ), + "pushover": ( + "pushover_enable", + "pushover_cats", + "pushover_token", + "pushover_userkey", + "pushover_device", + "pushover_prio_startup", + "pushover_prio_download", + "pushover_prio_pause_resume", + "pushover_prio_pp", + "pushover_prio_complete", + "pushover_prio_failed", + "pushover_prio_disk_full", + "pushover_prio_warning", + "pushover_prio_error", + "pushover_prio_queue_done", + "pushover_prio_other", + "pushover_prio_new_login", + "pushover_emergency_retry", + "pushover_emergency_expire", + ), + "pushbullet": ( + "pushbullet_enable", + "pushbullet_cats", + "pushbullet_apikey", + "pushbullet_device", + "pushbullet_prio_startup", + "pushbullet_prio_download", + "pushbullet_prio_pause_resume", + "pushbullet_prio_pp", + "pushbullet_prio_complete", + "pushbullet_prio_failed", + "pushbullet_prio_disk_full", + "pushbullet_prio_warning", + "pushbullet_prio_error", + "pushbullet_prio_queue_done", + "pushbullet_prio_other", + "pushbullet_prio_new_login", + ), + "nscript": ( + "nscript_enable", + "nscript_cats", + "nscript_script", + "nscript_parameters", + "nscript_prio_startup", + "nscript_prio_download", + "nscript_prio_pause_resume", + "nscript_prio_pp", + "nscript_prio_complete", + "nscript_prio_failed", + "nscript_prio_disk_full", + "nscript_prio_warning", + "nscript_prio_error", + "nscript_prio_queue_done", + "nscript_prio_other", + "nscript_prio_new_login", + ), +} class ConfigNotify: diff --git a/tests/test_functional_misc.py b/tests/test_functional_misc.py index 42f4ca2..f4ad8a8 100644 --- a/tests/test_functional_misc.py +++ b/tests/test_functional_misc.py @@ -32,7 +32,7 @@ class TestShowLogging(SABnzbdBaseTest): def test_showlog(self): """Test the output of the filtered-log button""" # Basic URL-fetching, easier than Selenium file download - log_result = get_url_result("status/showlog") + log_result = get_api_result("showlog", extra_arguments={"output": "text"}) # Make sure it has basic log stuff assert "The log" in log_result