Browse Source

Transfer /status/ functions to API-functions

TODO: Update documentation and maybe some tests
pull/1923/head
Safihre 4 years ago
parent
commit
2aa0dbd93d
  1. 14
      interfaces/Glitter/templates/include_overlays.tmpl
  2. 55
      interfaces/Glitter/templates/static/javascripts/glitter.main.js
  3. 1
      interfaces/Glitter/templates/status.tmpl
  4. 1
      sabnzbd/__init__.py
  5. 130
      sabnzbd/api.py
  6. 435
      sabnzbd/interface.py
  7. 2
      tests/test_functional_misc.py

14
interfaces/Glitter/templates/include_overlays.tmpl

@ -116,7 +116,7 @@
<div class="col-sm-6">$T('dashboard-systemPerformance') &nbsp; </div>
<div class="col-sm-6" data-bind="visible: hasPerformanceInfo">
<span data-bind="text: statusInfo.pystone"></span>
<a href="#" data-bind="click: testDiskSpeed" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<small data-bind="truncatedText: statusInfo.cpumodel, length: 25, attr: { 'data-original-title': statusInfo.cpumodel }" data-tooltip="true"></small>
</div>
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
@ -125,7 +125,7 @@
<div class="col-sm-6">$T('dashboard-downloadDirSpeed') &nbsp; </div>
<div class="col-sm-6" data-bind="visible: hasPerformanceInfo">
<span data-bind="text: statusInfo.downloaddirspeed()"></span> MB/s
<a href="#" class="diskspeed-button" data-bind="click: testDiskSpeed" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<small>(<span data-bind="truncatedText: statusInfo.downloaddir, length: 24, attr: { 'data-original-title': statusInfo.downloaddir }" data-tooltip="true"></span>)</small>
</div>
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
@ -134,7 +134,7 @@
<div class="col-sm-6">$T('dashboard-completeDirSpeed') &nbsp; </div>
<div class="col-sm-6" data-bind="visible: hasPerformanceInfo">
<span data-bind="text: statusInfo.completedirspeed()"></span> MB/s
<a href="#" class="diskspeed-button" data-bind="click: testDiskSpeed" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<small>(<span data-bind="truncatedText: statusInfo.completedir, length: 24, attr: { 'data-original-title': statusInfo.completedir }" data-tooltip="true"></span>)</small>
</div>
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
@ -143,7 +143,7 @@
<div class="col-sm-6">$T('dashboard-internetBandwidth') &nbsp; </div>
<div class="col-sm-6" data-bind="visible: hasPerformanceInfo">
<span data-bind="text: statusInfo.internetbandwidth()"></span> MB/s
<a href="#" class="diskspeed-button" data-bind="click: testDiskSpeed" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<a href="#" class="diskspeed-button" data-bind="click: loadStatusInfo" data-tooltip="true" data-placement="right" title="$T('dashboard-repeatTest')"><span class="glyphicon glyphicon-repeat"></span></a>
<small>(<span data-bind="text: statusInfo.internetbandwidth()*8"></span> Mbps)</small>
</div>
<div class="col-sm-6 col-loading" data-bind="visible: !hasPerformanceInfo()">$T('Glitter-loading')<span class="loader-dot-one">.</span><span class="loader-dot-two">.</span><span class="loader-dot-three">.</span></div>
@ -170,7 +170,7 @@
</div>
<div class="row options-function-box">
<div class="col-sm-6">
<a href="./status/showlog?apikey=$apikey" target="_blank" class="btn btn-default" data-tooltip="true" data-placement="top" title="$T('Glitter-logText')">
<a href="./api?mode=showlog&apikey=$apikey" target="_blank" class="btn btn-default" data-tooltip="true" data-placement="top" title="$T('Glitter-logText')">
<span class="glyphicon glyphicon-file"></span> $T('link-showLog')
</a>
</div>
@ -285,8 +285,8 @@
<tr>
<td><span class="glyphicon glyphicon-folder-open"></span></td>
<td class="row-wrap-text"><strong data-bind="html: \$data"></strong></td>
<td><a href="#" data-bind="click: \$root.folderProcess" data-action="add" class="hover-button" data-tooltip="true" data-placement="left" title="$T('Glitter-backToQueue')"><span class="glyphicon glyphicon-plus-sign"></span></a></td>
<td><a href="#" data-bind="click: \$root.folderProcess" data-action="delete" class="hover-button" data-tooltip="true" data-placement="left" title="$T('Glitter-deleteJobAndFolders')"><span class="glyphicon glyphicon-trash"></span></a></td>
<td><a href="#" data-bind="click: \$root.folderProcess" data-action="add_orphan" class="hover-button" data-tooltip="true" data-placement="left" title="$T('Glitter-backToQueue')"><span class="glyphicon glyphicon-plus-sign"></span></a></td>
<td><a href="#" data-bind="click: \$root.folderProcess" data-action="delete_orphan" class="hover-button" data-tooltip="true" data-placement="left" title="$T('Glitter-deleteJobAndFolders')"><span class="glyphicon glyphicon-trash"></span></a></td>
</tr>
</tbody>
</table>

55
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: $("<div/>").html(folder).text()
callAPI({
mode: "status",
name: $(htmlElement.currentTarget).data('action'),
value: $("<div/>").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)

1
interfaces/Glitter/templates/status.tmpl

@ -1 +0,0 @@
&nbsp;

1
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

130
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=<APIKEY>", log_data)
log_data = LOG_API_JSON_RE.sub(b"'apikey':<APIKEY>'", log_data)
log_data = LOG_USER_RE.sub(b"\\g<1>=<USER>", log_data)
log_data = LOG_PASS_RE.sub(b"password=<PASSWORD>", log_data)
log_data = LOG_INI_HIDE_RE.sub(b"\\1 = <REMOVED>", log_data)
log_data = LOG_HASH_RE.sub(b"<HASH>", log_data)
# Try to replace the username
try:
cur_user = getpass.getuser()
if cur_user:
log_data = log_data.replace(utob(cur_user), b"<USERNAME>")
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

435
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=<APIKEY>", log_data)
log_data = LOG_API_JSON_RE.sub(b"'apikey':<APIKEY>'", log_data)
log_data = LOG_USER_RE.sub(b"\\g<1>=<USER>", log_data)
log_data = LOG_PASS_RE.sub(b"password=<PASSWORD>", log_data)
log_data = LOG_INI_HIDE_RE.sub(b"\\1 = <REMOVED>", log_data)
log_data = LOG_HASH_RE.sub(b"<HASH>", 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"<USERNAME>")
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:

2
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

Loading…
Cancel
Save