Merge pull request #3598 from jef/jef/fix-str

fix: use `endwith()` instead of `endWith()`
This commit is contained in:
Adrian Sampson 2020-05-23 09:19:25 -04:00
commit 1b4686eebc
2 changed files with 154 additions and 43 deletions

View file

@ -35,47 +35,6 @@ from beets.plugins import BeetsPlugin
__author__ = 'https://github.com/maffo999'
def create_token():
"""Create salt and token from given password.
:return: The generated salt and hashed token
"""
password = config['subsonic']['pass'].as_str()
# Pick the random sequence and salt the password
r = string.ascii_letters + string.digits
salt = "".join([random.choice(r) for _ in range(6)])
salted_password = password + salt
token = hashlib.md5().update(salted_password.encode('utf-8')).hexdigest()
# Put together the payload of the request to the server and the URL
return salt, token
def format_url():
"""Get the Subsonic URL to trigger a scan. Uses either the url
config option or the deprecated host, port, and context_path config
options together.
:return: Endpoint for updating Subsonic
"""
url = config['subsonic']['url'].as_str()
if url and url.endsWith('/'):
url = url[:-1]
# @deprecated("Use url config option instead")
if not url:
host = config['subsonic']['host'].as_str()
port = config['subsonic']['port'].get(int)
context_path = config['subsonic']['contextpath'].as_str()
if context_path == '/':
context_path = ''
url = "http://{}:{}{}".format(host, port, context_path)
return url + '/rest/startScan'
class SubsonicUpdate(BeetsPlugin):
def __init__(self):
super(SubsonicUpdate, self).__init__()
@ -90,10 +49,51 @@ class SubsonicUpdate(BeetsPlugin):
config['subsonic']['pass'].redact = True
self.register_listener('import', self.start_scan)
@staticmethod
def __create_token():
"""Create salt and token from given password.
:return: The generated salt and hashed token
"""
password = config['subsonic']['pass'].as_str()
# Pick the random sequence and salt the password
r = string.ascii_letters + string.digits
salt = "".join([random.choice(r) for _ in range(6)])
salted_password = password + salt
token = hashlib.md5(salted_password.encode('utf-8')).hexdigest()
# Put together the payload of the request to the server and the URL
return salt, token
@staticmethod
def __format_url():
"""Get the Subsonic URL to trigger a scan. Uses either the url
config option or the deprecated host, port, and context_path config
options together.
:return: Endpoint for updating Subsonic
"""
url = config['subsonic']['url'].as_str()
if url and url.endswith('/'):
url = url[:-1]
# @deprecated("Use url config option instead")
if not url:
host = config['subsonic']['host'].as_str()
port = config['subsonic']['port'].get(int)
context_path = config['subsonic']['contextpath'].as_str()
if context_path == '/':
context_path = ''
url = "http://{}:{}{}".format(host, port, context_path)
return url + '/rest/startScan'
def start_scan(self):
user = config['subsonic']['user'].as_str()
url = format_url()
salt, token = create_token()
url = self.__format_url()
salt, token = self.__create_token()
payload = {
'u': user,

111
test/test_subsonic.py Normal file
View file

@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
"""Tests for the 'subsonic' plugin"""
from __future__ import division, absolute_import, print_function
import requests
import responses
import unittest
from test import _common
from beets import config
from beetsplug import subsonicupdate
from test.helper import TestHelper
from six.moves.urllib.parse import parse_qs, urlparse
class ArgumentsMock(object):
def __init__(self, mode, show_failures):
self.mode = mode
self.show_failures = show_failures
self.verbose = 1
def _params(url):
"""Get the query parameters from a URL."""
return parse_qs(urlparse(url).query)
class SubsonicPluginTest(_common.TestCase, TestHelper):
@responses.activate
def setUp(self):
config.clear()
self.setup_beets()
config["subsonic"]["user"] = "admin"
config["subsonic"]["pass"] = "admin"
config["subsonic"]["url"] = "http://localhost:4040"
self.subsonicupdate = subsonicupdate.SubsonicUpdate()
def tearDown(self):
self.teardown_beets()
@responses.activate
def test_start_scan(self):
responses.add(
responses.POST,
'http://localhost:4040/rest/startScan',
status=200
)
self.subsonicupdate.start_scan()
@responses.activate
def test_url_with_extra_forward_slash_url(self):
config["subsonic"]["url"] = "http://localhost:4040/contextPath"
responses.add(
responses.POST,
'http://localhost:4040/contextPath/rest/startScan',
status=200
)
self.subsonicupdate.start_scan()
@responses.activate
def test_url_with_context_path(self):
config["subsonic"]["url"] = "http://localhost:4040/"
responses.add(
responses.POST,
'http://localhost:4040/rest/startScan',
status=200
)
self.subsonicupdate.start_scan()
@responses.activate
def test_url_with_missing_port(self):
config["subsonic"]["url"] = "http://localhost/airsonic"
responses.add(
responses.POST,
'http://localhost:4040/rest/startScan',
status=200
)
with self.assertRaises(requests.exceptions.ConnectionError):
self.subsonicupdate.start_scan()
@responses.activate
def test_url_with_missing_schema(self):
config["subsonic"]["url"] = "localhost:4040/airsonic"
responses.add(
responses.POST,
'http://localhost:4040/rest/startScan',
status=200
)
with self.assertRaises(requests.exceptions.InvalidSchema):
self.subsonicupdate.start_scan()
def suite():
return unittest.TestLoader().loadTestsFromName(__name__)
if __name__ == '__main__':
unittest.main(defaultTest='suite')