forked from openlp/openlp
Add cetralised proxy support
bzr-revno: 2823
This commit is contained in:
commit
6a8bf83d27
@ -32,6 +32,7 @@ import requests
|
|||||||
|
|
||||||
from openlp.core.common import trace_error_handler
|
from openlp.core.common import trace_error_handler
|
||||||
from openlp.core.common.registry import Registry
|
from openlp.core.common.registry import Registry
|
||||||
|
from openlp.core.common.settings import ProxyMode, Settings
|
||||||
|
|
||||||
log = logging.getLogger(__name__ + '.__init__')
|
log = logging.getLogger(__name__ + '.__init__')
|
||||||
|
|
||||||
@ -64,6 +65,39 @@ CONNECTION_TIMEOUT = 30
|
|||||||
CONNECTION_RETRIES = 2
|
CONNECTION_RETRIES = 2
|
||||||
|
|
||||||
|
|
||||||
|
def get_proxy_settings(mode=None):
|
||||||
|
"""
|
||||||
|
Create a dictionary containing the proxy settings.
|
||||||
|
|
||||||
|
:param ProxyMode | None mode: Specify the source of the proxy settings
|
||||||
|
:return: A dict using the format expected by the requests library.
|
||||||
|
:rtype: dict | None
|
||||||
|
"""
|
||||||
|
settings = Settings()
|
||||||
|
if mode is None:
|
||||||
|
mode = settings.value('advanced/proxy mode')
|
||||||
|
if mode == ProxyMode.NO_PROXY:
|
||||||
|
return {'http': None, 'https': None}
|
||||||
|
elif mode == ProxyMode.SYSTEM_PROXY:
|
||||||
|
# The requests library defaults to using the proxy settings in the environment variables
|
||||||
|
return
|
||||||
|
elif mode == ProxyMode.MANUAL_PROXY:
|
||||||
|
http_addr = settings.value('advanced/proxy http')
|
||||||
|
https_addr = settings.value('advanced/proxy https')
|
||||||
|
username = settings.value('advanced/proxy username')
|
||||||
|
password = settings.value('advanced/proxy password')
|
||||||
|
basic_auth = ''
|
||||||
|
if username:
|
||||||
|
basic_auth = '{username}:{password}@'.format(username=username, password=password)
|
||||||
|
http_value = None
|
||||||
|
https_value = None
|
||||||
|
if http_addr:
|
||||||
|
http_value = 'http://{basic_auth}{http_addr}'.format(basic_auth=basic_auth, http_addr=http_addr)
|
||||||
|
if https_addr:
|
||||||
|
https_value = 'https://{basic_auth}{https_addr}'.format(basic_auth=basic_auth, https_addr=https_addr)
|
||||||
|
return {'http': http_value, 'https': https_value}
|
||||||
|
|
||||||
|
|
||||||
def get_user_agent():
|
def get_user_agent():
|
||||||
"""
|
"""
|
||||||
Return a user agent customised for the platform the user is on.
|
Return a user agent customised for the platform the user is on.
|
||||||
@ -75,14 +109,15 @@ def get_user_agent():
|
|||||||
return browser_list[random_index]
|
return browser_list[random_index]
|
||||||
|
|
||||||
|
|
||||||
def get_web_page(url, headers=None, update_openlp=False, proxies=None):
|
def get_web_page(url, headers=None, update_openlp=False, proxy=None):
|
||||||
"""
|
"""
|
||||||
Attempts to download the webpage at url and returns that page or None.
|
Attempts to download the webpage at url and returns that page or None.
|
||||||
|
|
||||||
:param url: The URL to be downloaded.
|
:param url: The URL to be downloaded.
|
||||||
:param header: An optional HTTP header to pass in the request to the web server.
|
:param dict | None headers: An optional HTTP header to pass in the request to the web server.
|
||||||
:param update_openlp: Tells OpenLP to update itself if the page is successfully downloaded.
|
:param update_openlp: Tells OpenLP to update itself if the page is successfully downloaded. Defaults to False.
|
||||||
Defaults to False.
|
:param dict | ProxyMode | None proxy: ProxyMode enum or a dictionary containing the proxy servers, with their types
|
||||||
|
as the key e.g. {'http': 'http://proxyserver:port', 'https': 'https://proxyserver:port'}
|
||||||
"""
|
"""
|
||||||
if not url:
|
if not url:
|
||||||
return None
|
return None
|
||||||
@ -90,11 +125,13 @@ def get_web_page(url, headers=None, update_openlp=False, proxies=None):
|
|||||||
headers = {}
|
headers = {}
|
||||||
if 'user-agent' not in [key.lower() for key in headers.keys()]:
|
if 'user-agent' not in [key.lower() for key in headers.keys()]:
|
||||||
headers['User-Agent'] = get_user_agent()
|
headers['User-Agent'] = get_user_agent()
|
||||||
|
if not isinstance(proxy, dict):
|
||||||
|
proxy = get_proxy_settings(mode=proxy)
|
||||||
log.debug('Downloading URL = %s' % url)
|
log.debug('Downloading URL = %s' % url)
|
||||||
retries = 0
|
retries = 0
|
||||||
while retries < CONNECTION_RETRIES:
|
while retries < CONNECTION_RETRIES:
|
||||||
try:
|
try:
|
||||||
response = requests.get(url, headers=headers, proxies=proxies, timeout=float(CONNECTION_TIMEOUT))
|
response = requests.get(url, headers=headers, proxies=proxy, timeout=float(CONNECTION_TIMEOUT))
|
||||||
log.debug('Downloaded page {url}'.format(url=response.url))
|
log.debug('Downloaded page {url}'.format(url=response.url))
|
||||||
break
|
break
|
||||||
except OSError:
|
except OSError:
|
||||||
|
@ -26,6 +26,7 @@ import datetime
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
from enum import IntEnum
|
||||||
from tempfile import gettempdir
|
from tempfile import gettempdir
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui
|
from PyQt5 import QtCore, QtGui
|
||||||
@ -38,6 +39,13 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
__version__ = 2
|
__version__ = 2
|
||||||
|
|
||||||
|
|
||||||
|
class ProxyMode(IntEnum):
|
||||||
|
NO_PROXY = 1
|
||||||
|
SYSTEM_PROXY = 2
|
||||||
|
MANUAL_PROXY = 3
|
||||||
|
|
||||||
|
|
||||||
# Fix for bug #1014422.
|
# Fix for bug #1014422.
|
||||||
X11_BYPASS_DEFAULT = True
|
X11_BYPASS_DEFAULT = True
|
||||||
if is_linux(): # pragma: no cover
|
if is_linux(): # pragma: no cover
|
||||||
@ -116,6 +124,11 @@ class Settings(QtCore.QSettings):
|
|||||||
'advanced/print file meta data': False,
|
'advanced/print file meta data': False,
|
||||||
'advanced/print notes': False,
|
'advanced/print notes': False,
|
||||||
'advanced/print slide text': False,
|
'advanced/print slide text': False,
|
||||||
|
'advanced/proxy mode': ProxyMode.SYSTEM_PROXY,
|
||||||
|
'advanced/proxy http': '',
|
||||||
|
'advanced/proxy https': '',
|
||||||
|
'advanced/proxy username': '',
|
||||||
|
'advanced/proxy password': '',
|
||||||
'advanced/recent file count': 4,
|
'advanced/recent file count': 4,
|
||||||
'advanced/save current plugin': False,
|
'advanced/save current plugin': False,
|
||||||
'advanced/slide limits': SlideLimits.End,
|
'advanced/slide limits': SlideLimits.End,
|
||||||
|
@ -35,6 +35,7 @@ from openlp.core.lib import SettingsTab, build_icon
|
|||||||
from openlp.core.ui.style import HAS_DARK_STYLE
|
from openlp.core.ui.style import HAS_DARK_STYLE
|
||||||
from openlp.core.widgets.edits import PathEdit
|
from openlp.core.widgets.edits import PathEdit
|
||||||
from openlp.core.widgets.enums import PathEditType
|
from openlp.core.widgets.enums import PathEditType
|
||||||
|
from openlp.core.widgets.widgets import ProxyWidget
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -76,6 +77,9 @@ class AdvancedTab(SettingsTab):
|
|||||||
self.media_plugin_check_box = QtWidgets.QCheckBox(self.ui_group_box)
|
self.media_plugin_check_box = QtWidgets.QCheckBox(self.ui_group_box)
|
||||||
self.media_plugin_check_box.setObjectName('media_plugin_check_box')
|
self.media_plugin_check_box.setObjectName('media_plugin_check_box')
|
||||||
self.ui_layout.addRow(self.media_plugin_check_box)
|
self.ui_layout.addRow(self.media_plugin_check_box)
|
||||||
|
self.hide_mouse_check_box = QtWidgets.QCheckBox(self.ui_group_box)
|
||||||
|
self.hide_mouse_check_box.setObjectName('hide_mouse_check_box')
|
||||||
|
self.ui_layout.addWidget(self.hide_mouse_check_box)
|
||||||
self.double_click_live_check_box = QtWidgets.QCheckBox(self.ui_group_box)
|
self.double_click_live_check_box = QtWidgets.QCheckBox(self.ui_group_box)
|
||||||
self.double_click_live_check_box.setObjectName('double_click_live_check_box')
|
self.double_click_live_check_box.setObjectName('double_click_live_check_box')
|
||||||
self.ui_layout.addRow(self.double_click_live_check_box)
|
self.ui_layout.addRow(self.double_click_live_check_box)
|
||||||
@ -116,6 +120,24 @@ class AdvancedTab(SettingsTab):
|
|||||||
self.use_dark_style_checkbox = QtWidgets.QCheckBox(self.ui_group_box)
|
self.use_dark_style_checkbox = QtWidgets.QCheckBox(self.ui_group_box)
|
||||||
self.use_dark_style_checkbox.setObjectName('use_dark_style_checkbox')
|
self.use_dark_style_checkbox.setObjectName('use_dark_style_checkbox')
|
||||||
self.ui_layout.addRow(self.use_dark_style_checkbox)
|
self.ui_layout.addRow(self.use_dark_style_checkbox)
|
||||||
|
# Service Item Slide Limits
|
||||||
|
self.slide_group_box = QtWidgets.QGroupBox(self.left_column)
|
||||||
|
self.slide_group_box.setObjectName('slide_group_box')
|
||||||
|
self.slide_layout = QtWidgets.QVBoxLayout(self.slide_group_box)
|
||||||
|
self.slide_layout.setObjectName('slide_layout')
|
||||||
|
self.slide_label = QtWidgets.QLabel(self.slide_group_box)
|
||||||
|
self.slide_label.setWordWrap(True)
|
||||||
|
self.slide_layout.addWidget(self.slide_label)
|
||||||
|
self.end_slide_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
|
||||||
|
self.end_slide_radio_button.setObjectName('end_slide_radio_button')
|
||||||
|
self.slide_layout.addWidget(self.end_slide_radio_button)
|
||||||
|
self.wrap_slide_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
|
||||||
|
self.wrap_slide_radio_button.setObjectName('wrap_slide_radio_button')
|
||||||
|
self.slide_layout.addWidget(self.wrap_slide_radio_button)
|
||||||
|
self.next_item_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
|
||||||
|
self.next_item_radio_button.setObjectName('next_item_radio_button')
|
||||||
|
self.slide_layout.addWidget(self.next_item_radio_button)
|
||||||
|
self.left_layout.addWidget(self.slide_group_box)
|
||||||
# Data Directory
|
# Data Directory
|
||||||
self.data_directory_group_box = QtWidgets.QGroupBox(self.left_column)
|
self.data_directory_group_box = QtWidgets.QGroupBox(self.left_column)
|
||||||
self.data_directory_group_box.setObjectName('data_directory_group_box')
|
self.data_directory_group_box.setObjectName('data_directory_group_box')
|
||||||
@ -142,33 +164,6 @@ class AdvancedTab(SettingsTab):
|
|||||||
self.data_directory_layout.addRow(self.data_directory_copy_check_layout)
|
self.data_directory_layout.addRow(self.data_directory_copy_check_layout)
|
||||||
self.data_directory_layout.addRow(self.new_data_directory_has_files_label)
|
self.data_directory_layout.addRow(self.new_data_directory_has_files_label)
|
||||||
self.left_layout.addWidget(self.data_directory_group_box)
|
self.left_layout.addWidget(self.data_directory_group_box)
|
||||||
# Hide mouse
|
|
||||||
self.hide_mouse_group_box = QtWidgets.QGroupBox(self.right_column)
|
|
||||||
self.hide_mouse_group_box.setObjectName('hide_mouse_group_box')
|
|
||||||
self.hide_mouse_layout = QtWidgets.QVBoxLayout(self.hide_mouse_group_box)
|
|
||||||
self.hide_mouse_layout.setObjectName('hide_mouse_layout')
|
|
||||||
self.hide_mouse_check_box = QtWidgets.QCheckBox(self.hide_mouse_group_box)
|
|
||||||
self.hide_mouse_check_box.setObjectName('hide_mouse_check_box')
|
|
||||||
self.hide_mouse_layout.addWidget(self.hide_mouse_check_box)
|
|
||||||
self.right_layout.addWidget(self.hide_mouse_group_box)
|
|
||||||
# Service Item Slide Limits
|
|
||||||
self.slide_group_box = QtWidgets.QGroupBox(self.right_column)
|
|
||||||
self.slide_group_box.setObjectName('slide_group_box')
|
|
||||||
self.slide_layout = QtWidgets.QVBoxLayout(self.slide_group_box)
|
|
||||||
self.slide_layout.setObjectName('slide_layout')
|
|
||||||
self.slide_label = QtWidgets.QLabel(self.slide_group_box)
|
|
||||||
self.slide_label.setWordWrap(True)
|
|
||||||
self.slide_layout.addWidget(self.slide_label)
|
|
||||||
self.end_slide_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
|
|
||||||
self.end_slide_radio_button.setObjectName('end_slide_radio_button')
|
|
||||||
self.slide_layout.addWidget(self.end_slide_radio_button)
|
|
||||||
self.wrap_slide_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
|
|
||||||
self.wrap_slide_radio_button.setObjectName('wrap_slide_radio_button')
|
|
||||||
self.slide_layout.addWidget(self.wrap_slide_radio_button)
|
|
||||||
self.next_item_radio_button = QtWidgets.QRadioButton(self.slide_group_box)
|
|
||||||
self.next_item_radio_button.setObjectName('next_item_radio_button')
|
|
||||||
self.slide_layout.addWidget(self.next_item_radio_button)
|
|
||||||
self.right_layout.addWidget(self.slide_group_box)
|
|
||||||
# Display Workarounds
|
# Display Workarounds
|
||||||
self.display_workaround_group_box = QtWidgets.QGroupBox(self.right_column)
|
self.display_workaround_group_box = QtWidgets.QGroupBox(self.right_column)
|
||||||
self.display_workaround_group_box.setObjectName('display_workaround_group_box')
|
self.display_workaround_group_box.setObjectName('display_workaround_group_box')
|
||||||
@ -223,6 +218,9 @@ class AdvancedTab(SettingsTab):
|
|||||||
self.service_name_example.setObjectName('service_name_example')
|
self.service_name_example.setObjectName('service_name_example')
|
||||||
self.service_name_layout.addRow(self.service_name_example_label, self.service_name_example)
|
self.service_name_layout.addRow(self.service_name_example_label, self.service_name_example)
|
||||||
self.right_layout.addWidget(self.service_name_group_box)
|
self.right_layout.addWidget(self.service_name_group_box)
|
||||||
|
# Proxies
|
||||||
|
self.proxy_widget = ProxyWidget(self.right_column)
|
||||||
|
self.right_layout.addWidget(self.proxy_widget)
|
||||||
# After the last item on each side, add some spacing
|
# After the last item on each side, add some spacing
|
||||||
self.left_layout.addStretch()
|
self.left_layout.addStretch()
|
||||||
self.right_layout.addStretch()
|
self.right_layout.addStretch()
|
||||||
@ -311,7 +309,6 @@ class AdvancedTab(SettingsTab):
|
|||||||
translate('OpenLP.AdvancedTab',
|
translate('OpenLP.AdvancedTab',
|
||||||
'Revert to the default service name "{name}".').format(name=UiStrings().DefaultServiceName))
|
'Revert to the default service name "{name}".').format(name=UiStrings().DefaultServiceName))
|
||||||
self.service_name_example_label.setText(translate('OpenLP.AdvancedTab', 'Example:'))
|
self.service_name_example_label.setText(translate('OpenLP.AdvancedTab', 'Example:'))
|
||||||
self.hide_mouse_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Mouse Cursor'))
|
|
||||||
self.hide_mouse_check_box.setText(translate('OpenLP.AdvancedTab', 'Hide mouse cursor when over display window'))
|
self.hide_mouse_check_box.setText(translate('OpenLP.AdvancedTab', 'Hide mouse cursor when over display window'))
|
||||||
self.data_directory_new_label.setText(translate('OpenLP.AdvancedTab', 'Path:'))
|
self.data_directory_new_label.setText(translate('OpenLP.AdvancedTab', 'Path:'))
|
||||||
self.data_directory_cancel_button.setText(translate('OpenLP.AdvancedTab', 'Cancel'))
|
self.data_directory_cancel_button.setText(translate('OpenLP.AdvancedTab', 'Cancel'))
|
||||||
@ -334,6 +331,7 @@ class AdvancedTab(SettingsTab):
|
|||||||
self.wrap_slide_radio_button.setText(translate('OpenLP.GeneralTab', '&Wrap around'))
|
self.wrap_slide_radio_button.setText(translate('OpenLP.GeneralTab', '&Wrap around'))
|
||||||
self.next_item_radio_button.setText(translate('OpenLP.GeneralTab', '&Move to next/previous service item'))
|
self.next_item_radio_button.setText(translate('OpenLP.GeneralTab', '&Move to next/previous service item'))
|
||||||
self.search_as_type_check_box.setText(translate('SongsPlugin.GeneralTab', 'Enable search as you type'))
|
self.search_as_type_check_box.setText(translate('SongsPlugin.GeneralTab', 'Enable search as you type'))
|
||||||
|
self.proxy_widget.retranslate_ui()
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
"""
|
"""
|
||||||
@ -436,6 +434,7 @@ class AdvancedTab(SettingsTab):
|
|||||||
if HAS_DARK_STYLE:
|
if HAS_DARK_STYLE:
|
||||||
settings.setValue('use_dark_style', self.use_dark_style_checkbox.isChecked())
|
settings.setValue('use_dark_style', self.use_dark_style_checkbox.isChecked())
|
||||||
settings.endGroup()
|
settings.endGroup()
|
||||||
|
self.proxy_widget.save()
|
||||||
|
|
||||||
def on_search_as_type_check_box_changed(self, check_state):
|
def on_search_as_type_check_box_changed(self, check_state):
|
||||||
self.is_search_as_you_type_enabled = (check_state == QtCore.Qt.Checked)
|
self.is_search_as_you_type_enabled = (check_state == QtCore.Qt.Checked)
|
||||||
|
132
openlp/core/widgets/widgets.py
Normal file
132
openlp/core/widgets/widgets.py
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2018 OpenLP Developers #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# This program is free software; you can redistribute it and/or modify it #
|
||||||
|
# under the terms of the GNU General Public License as published by the Free #
|
||||||
|
# Software Foundation; version 2 of the License. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||||
|
# more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License along #
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||||
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
|
###############################################################################
|
||||||
|
"""
|
||||||
|
The :mod:`~openlp.core.widgets.widgets` module contains custom widgets used in OpenLP
|
||||||
|
"""
|
||||||
|
from PyQt5 import QtWidgets
|
||||||
|
|
||||||
|
from openlp.core.common.i18n import translate
|
||||||
|
from openlp.core.common.settings import ProxyMode, Settings
|
||||||
|
|
||||||
|
|
||||||
|
class ProxyWidget(QtWidgets.QGroupBox):
|
||||||
|
"""
|
||||||
|
A proxy settings widget that implements loading and saving its settings.
|
||||||
|
"""
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
"""
|
||||||
|
Initialise the widget.
|
||||||
|
|
||||||
|
:param QtWidgets.QWidget | None parent: The widgets parent
|
||||||
|
"""
|
||||||
|
super().__init__(parent)
|
||||||
|
self._setup()
|
||||||
|
|
||||||
|
def _setup(self):
|
||||||
|
"""
|
||||||
|
A setup method seperate from __init__ to allow easier testing
|
||||||
|
"""
|
||||||
|
self.setup_ui()
|
||||||
|
self.load()
|
||||||
|
|
||||||
|
def setup_ui(self):
|
||||||
|
"""
|
||||||
|
Create the widget layout and sub widgets
|
||||||
|
"""
|
||||||
|
self.layout = QtWidgets.QFormLayout(self)
|
||||||
|
self.radio_group = QtWidgets.QButtonGroup(self)
|
||||||
|
self.no_proxy_radio = QtWidgets.QRadioButton('', self)
|
||||||
|
self.radio_group.addButton(self.no_proxy_radio, ProxyMode.NO_PROXY)
|
||||||
|
self.layout.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.no_proxy_radio)
|
||||||
|
self.use_sysem_proxy_radio = QtWidgets.QRadioButton('', self)
|
||||||
|
self.radio_group.addButton(self.use_sysem_proxy_radio, ProxyMode.SYSTEM_PROXY)
|
||||||
|
self.layout.setWidget(1, QtWidgets.QFormLayout.SpanningRole, self.use_sysem_proxy_radio)
|
||||||
|
self.manual_proxy_radio = QtWidgets.QRadioButton('', self)
|
||||||
|
self.radio_group.addButton(self.manual_proxy_radio, ProxyMode.MANUAL_PROXY)
|
||||||
|
self.layout.setWidget(2, QtWidgets.QFormLayout.SpanningRole, self.manual_proxy_radio)
|
||||||
|
self.http_edit = QtWidgets.QLineEdit(self)
|
||||||
|
self.layout.addRow('HTTP:', self.http_edit)
|
||||||
|
self.https_edit = QtWidgets.QLineEdit(self)
|
||||||
|
self.layout.addRow('HTTPS:', self.https_edit)
|
||||||
|
self.username_edit = QtWidgets.QLineEdit(self)
|
||||||
|
self.layout.addRow('Username:', self.username_edit)
|
||||||
|
self.password_edit = QtWidgets.QLineEdit(self)
|
||||||
|
self.password_edit.setEchoMode(QtWidgets.QLineEdit.Password)
|
||||||
|
self.layout.addRow('Password:', self.password_edit)
|
||||||
|
# Signal / Slots
|
||||||
|
self.radio_group.buttonToggled.connect(self.on_radio_group_button_toggled)
|
||||||
|
|
||||||
|
def on_radio_group_button_toggled(self, button, checked):
|
||||||
|
"""
|
||||||
|
Handles the toggled signal on the radio buttons. The signal is emitted twice if a radio butting being toggled on
|
||||||
|
causes another radio button in the group to be toggled off.
|
||||||
|
|
||||||
|
En/Disables the `Manual Proxy` line edits depending on the currently selected radio button
|
||||||
|
|
||||||
|
:param QtWidgets.QRadioButton button: The button that has toggled
|
||||||
|
:param bool checked: The buttons new state
|
||||||
|
"""
|
||||||
|
id = self.radio_group.id(button) # The work around (see above comment)
|
||||||
|
enable_manual_edits = id == ProxyMode.MANUAL_PROXY and checked
|
||||||
|
self.http_edit.setEnabled(enable_manual_edits)
|
||||||
|
self.https_edit.setEnabled(enable_manual_edits)
|
||||||
|
self.username_edit.setEnabled(enable_manual_edits)
|
||||||
|
self.password_edit.setEnabled(enable_manual_edits)
|
||||||
|
|
||||||
|
def retranslate_ui(self):
|
||||||
|
"""
|
||||||
|
Translate the Ui
|
||||||
|
"""
|
||||||
|
self.setTitle(translate('OpenLP.ProxyWidget', 'Proxy Server Settings'))
|
||||||
|
self.no_proxy_radio.setText(translate('OpenLP.ProxyWidget', 'No prox&y'))
|
||||||
|
self.use_sysem_proxy_radio.setText(translate('OpenLP.ProxyWidget', '&Use system proxy'))
|
||||||
|
self.manual_proxy_radio.setText(translate('OpenLP.ProxyWidget', '&Manual proxy configuration'))
|
||||||
|
proxy_example = translate('OpenLP.ProxyWidget', 'e.g. proxy_server_address:port_no')
|
||||||
|
self.layout.labelForField(self.http_edit).setText(translate('OpenLP.ProxyWidget', 'HTTP:'))
|
||||||
|
self.http_edit.setPlaceholderText(proxy_example)
|
||||||
|
self.layout.labelForField(self.https_edit).setText(translate('OpenLP.ProxyWidget', 'HTTPS:'))
|
||||||
|
self.https_edit.setPlaceholderText(proxy_example)
|
||||||
|
self.layout.labelForField(self.username_edit).setText(translate('OpenLP.ProxyWidget', 'Username:'))
|
||||||
|
self.layout.labelForField(self.password_edit).setText(translate('OpenLP.ProxyWidget', 'Password:'))
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
"""
|
||||||
|
Load the data from the settings to the widget.
|
||||||
|
"""
|
||||||
|
settings = Settings()
|
||||||
|
checked_radio = self.radio_group.button(settings.value('advanced/proxy mode'))
|
||||||
|
checked_radio.setChecked(True)
|
||||||
|
self.http_edit.setText(settings.value('advanced/proxy http'))
|
||||||
|
self.https_edit.setText(settings.value('advanced/proxy https'))
|
||||||
|
self.username_edit.setText(settings.value('advanced/proxy username'))
|
||||||
|
self.password_edit.setText(settings.value('advanced/proxy password'))
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
"""
|
||||||
|
Save the widget data to the settings
|
||||||
|
"""
|
||||||
|
settings = Settings() # TODO: Migrate from old system
|
||||||
|
settings.setValue('advanced/proxy mode', self.radio_group.checkedId())
|
||||||
|
settings.setValue('advanced/proxy http', self.http_edit.text())
|
||||||
|
settings.setValue('advanced/proxy https', self.https_edit.text())
|
||||||
|
settings.setValue('advanced/proxy username', self.username_edit.text())
|
||||||
|
settings.setValue('advanced/proxy password', self.password_edit.text())
|
@ -27,13 +27,14 @@ import tempfile
|
|||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
from openlp.core.common.httputils import get_user_agent, get_web_page, get_url_file_size, download_file
|
from openlp.core.common.httputils import ProxyMode, download_file, get_proxy_settings, get_url_file_size, \
|
||||||
|
get_user_agent, get_web_page
|
||||||
from openlp.core.common.path import Path
|
from openlp.core.common.path import Path
|
||||||
|
from openlp.core.common.settings import Settings
|
||||||
from tests.helpers.testmixin import TestMixin
|
from tests.helpers.testmixin import TestMixin
|
||||||
|
|
||||||
|
|
||||||
class TestHttpUtils(TestCase, TestMixin):
|
class TestHttpUtils(TestCase, TestMixin):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
A test suite to test out various http helper functions.
|
A test suite to test out various http helper functions.
|
||||||
"""
|
"""
|
||||||
@ -240,3 +241,119 @@ class TestHttpUtils(TestCase, TestMixin):
|
|||||||
# THEN: socket.timeout should have been caught
|
# THEN: socket.timeout should have been caught
|
||||||
# NOTE: Test is if $tmpdir/tempfile is still there, then test fails since ftw deletes bad downloaded files
|
# NOTE: Test is if $tmpdir/tempfile is still there, then test fails since ftw deletes bad downloaded files
|
||||||
assert os.path.exists(self.tempfile) is False, 'tempfile should have been deleted'
|
assert os.path.exists(self.tempfile) is False, 'tempfile should have been deleted'
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetProxySettings(TestCase, TestMixin):
|
||||||
|
def setUp(self):
|
||||||
|
self.build_settings()
|
||||||
|
self.addCleanup(self.destroy_settings)
|
||||||
|
|
||||||
|
@patch('openlp.core.common.httputils.Settings')
|
||||||
|
def test_mode_arg_specified(self, MockSettings):
|
||||||
|
"""
|
||||||
|
Test that the argument is used rather than reading the 'advanced/proxy mode' setting
|
||||||
|
"""
|
||||||
|
# GIVEN: Mocked settings
|
||||||
|
mocked_settings = MagicMock()
|
||||||
|
MockSettings.return_value = mocked_settings
|
||||||
|
|
||||||
|
# WHEN: Calling `get_proxy_settings` with the mode arg specified
|
||||||
|
get_proxy_settings(mode=ProxyMode.NO_PROXY)
|
||||||
|
|
||||||
|
# THEN: The mode arg should have been used rather than looking it up in the settings
|
||||||
|
mocked_settings.value.assert_not_called()
|
||||||
|
|
||||||
|
@patch('openlp.core.common.httputils.Settings')
|
||||||
|
def test_mode_incorrect_arg_specified(self, MockSettings):
|
||||||
|
"""
|
||||||
|
Test that the system settings are used when the mode arg specieied is invalid
|
||||||
|
"""
|
||||||
|
# GIVEN: Mocked settings
|
||||||
|
mocked_settings = MagicMock()
|
||||||
|
MockSettings.return_value = mocked_settings
|
||||||
|
|
||||||
|
# WHEN: Calling `get_proxy_settings` with an invalid mode arg specified
|
||||||
|
result = get_proxy_settings(mode='qwerty')
|
||||||
|
|
||||||
|
# THEN: An None should be returned
|
||||||
|
mocked_settings.value.assert_not_called()
|
||||||
|
assert result is None
|
||||||
|
|
||||||
|
def test_no_proxy_mode(self):
|
||||||
|
"""
|
||||||
|
Test that a dictionary with http and https values are set to None is returned, when `NO_PROXY` mode is specified
|
||||||
|
"""
|
||||||
|
# GIVEN: A `proxy mode` setting of NO_PROXY
|
||||||
|
Settings().setValue('advanced/proxy mode', ProxyMode.NO_PROXY)
|
||||||
|
|
||||||
|
# WHEN: Calling `get_proxy_settings`
|
||||||
|
result = get_proxy_settings()
|
||||||
|
|
||||||
|
# THEN: The returned value should be a dictionary with http and https values set to None
|
||||||
|
assert result == {'http': None, 'https': None}
|
||||||
|
|
||||||
|
def test_system_proxy_mode(self):
|
||||||
|
"""
|
||||||
|
Test that None is returned, when `SYSTEM_PROXY` mode is specified
|
||||||
|
"""
|
||||||
|
# GIVEN: A `proxy mode` setting of SYSTEM_PROXY
|
||||||
|
Settings().setValue('advanced/proxy mode', ProxyMode.SYSTEM_PROXY)
|
||||||
|
|
||||||
|
# WHEN: Calling `get_proxy_settings`
|
||||||
|
result = get_proxy_settings()
|
||||||
|
|
||||||
|
# THEN: The returned value should be None
|
||||||
|
assert result is None
|
||||||
|
|
||||||
|
def test_manual_proxy_mode_no_auth(self):
|
||||||
|
"""
|
||||||
|
Test that the correct proxy addresses are returned when basic authentication is not used
|
||||||
|
"""
|
||||||
|
# GIVEN: A `proxy mode` setting of MANUAL_PROXY with proxy servers, but no auth credentials are supplied
|
||||||
|
Settings().setValue('advanced/proxy mode', ProxyMode.MANUAL_PROXY)
|
||||||
|
Settings().setValue('advanced/proxy http', 'testhttp.server:port')
|
||||||
|
Settings().setValue('advanced/proxy https', 'testhttps.server:port')
|
||||||
|
Settings().setValue('advanced/proxy username', '')
|
||||||
|
Settings().setValue('advanced/proxy password', '')
|
||||||
|
|
||||||
|
# WHEN: Calling `get_proxy_settings`
|
||||||
|
result = get_proxy_settings()
|
||||||
|
|
||||||
|
# THEN: The returned value should be the proxy servers without authentication
|
||||||
|
assert result == {'http': 'http://testhttp.server:port', 'https': 'https://testhttps.server:port'}
|
||||||
|
|
||||||
|
def test_manual_proxy_mode_auth(self):
|
||||||
|
"""
|
||||||
|
Test that the correct proxy addresses are returned when basic authentication is used
|
||||||
|
"""
|
||||||
|
# GIVEN: A `proxy mode` setting of MANUAL_PROXY with proxy servers and auth credentials supplied
|
||||||
|
Settings().setValue('advanced/proxy mode', ProxyMode.MANUAL_PROXY)
|
||||||
|
Settings().setValue('advanced/proxy http', 'testhttp.server:port')
|
||||||
|
Settings().setValue('advanced/proxy https', 'testhttps.server:port')
|
||||||
|
Settings().setValue('advanced/proxy username', 'user')
|
||||||
|
Settings().setValue('advanced/proxy password', 'pass')
|
||||||
|
|
||||||
|
# WHEN: Calling `get_proxy_settings`
|
||||||
|
result = get_proxy_settings()
|
||||||
|
|
||||||
|
# THEN: The returned value should be the proxy servers with the authentication credentials
|
||||||
|
assert result == {'http': 'http://user:pass@testhttp.server:port',
|
||||||
|
'https': 'https://user:pass@testhttps.server:port'}
|
||||||
|
|
||||||
|
def test_manual_proxy_mode_no_servers(self):
|
||||||
|
"""
|
||||||
|
Test that the system proxies are overidden when the MANUAL_PROXY mode is specified, but no server addresses are
|
||||||
|
supplied
|
||||||
|
"""
|
||||||
|
# GIVEN: A `proxy mode` setting of MANUAL_PROXY with no servers specified
|
||||||
|
Settings().setValue('advanced/proxy mode', ProxyMode.MANUAL_PROXY)
|
||||||
|
Settings().setValue('advanced/proxy http', '')
|
||||||
|
Settings().setValue('advanced/proxy https', '')
|
||||||
|
Settings().setValue('advanced/proxy username', 'user')
|
||||||
|
Settings().setValue('advanced/proxy password', 'pass')
|
||||||
|
|
||||||
|
# WHEN: Calling `get_proxy_settings`
|
||||||
|
result = get_proxy_settings()
|
||||||
|
|
||||||
|
# THEN: The returned value should be the proxy servers set to None
|
||||||
|
assert result == {'http': None, 'https': None}
|
||||||
|
174
tests/interfaces/openlp_core/widgets/test_widgets.py
Normal file
174
tests/interfaces/openlp_core/widgets/test_widgets.py
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# OpenLP - Open Source Lyrics Projection #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Copyright (c) 2008-2018 OpenLP Developers #
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# This program is free software; you can redistribute it and/or modify it #
|
||||||
|
# under the terms of the GNU General Public License as published by the Free #
|
||||||
|
# Software Foundation; version 2 of the License. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||||||
|
# more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License along #
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||||
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||||
|
###############################################################################
|
||||||
|
"""
|
||||||
|
Module to test the custom widgets.
|
||||||
|
"""
|
||||||
|
from unittest import TestCase
|
||||||
|
from unittest.mock import MagicMock, call, patch
|
||||||
|
|
||||||
|
from openlp.core.common.registry import Registry
|
||||||
|
from openlp.core.common.settings import ProxyMode
|
||||||
|
from openlp.core.widgets.widgets import ProxyWidget
|
||||||
|
from tests.helpers.testmixin import TestMixin
|
||||||
|
|
||||||
|
|
||||||
|
class TestProxyWidget(TestCase, TestMixin):
|
||||||
|
"""
|
||||||
|
Test the EditCustomForm.
|
||||||
|
"""
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Create the UI
|
||||||
|
"""
|
||||||
|
Registry.create()
|
||||||
|
self.setup_application()
|
||||||
|
|
||||||
|
def test_radio_button_exclusivity_no_proxy(self):
|
||||||
|
"""
|
||||||
|
Test that only one radio button can be checked at a time, and that the line edits are only enabled when the
|
||||||
|
`manual_proxy_radio` is checked
|
||||||
|
"""
|
||||||
|
# GIVEN: An instance of the `openlp.core.common.widgets.widgets.ProxyWidget` with a radio already checked
|
||||||
|
proxy_widget = ProxyWidget()
|
||||||
|
proxy_widget.manual_proxy_radio.setChecked(True)
|
||||||
|
|
||||||
|
# WHEN: 'Checking' the `no_proxy_radio` button
|
||||||
|
proxy_widget.no_proxy_radio.setChecked(True)
|
||||||
|
|
||||||
|
# THEN: The other radio buttons should not be checked and the line edits should not be enabled
|
||||||
|
assert proxy_widget.use_sysem_proxy_radio.isChecked() is False
|
||||||
|
assert proxy_widget.manual_proxy_radio.isChecked() is False
|
||||||
|
assert proxy_widget.http_edit.isEnabled() is False
|
||||||
|
assert proxy_widget.https_edit.isEnabled() is False
|
||||||
|
assert proxy_widget.username_edit.isEnabled() is False
|
||||||
|
assert proxy_widget.password_edit.isEnabled() is False
|
||||||
|
|
||||||
|
def test_radio_button_exclusivity_system_proxy(self):
|
||||||
|
"""
|
||||||
|
Test that only one radio button can be checked at a time, and that the line edits are only enabled when the
|
||||||
|
`manual_proxy_radio` is checked
|
||||||
|
"""
|
||||||
|
# GIVEN: An instance of the `openlp.core.common.widgets.widgets.ProxyWidget` with a radio already checked
|
||||||
|
proxy_widget = ProxyWidget()
|
||||||
|
proxy_widget.manual_proxy_radio.setChecked(True)
|
||||||
|
|
||||||
|
# WHEN: 'Checking' the `use_sysem_proxy_radio` button
|
||||||
|
proxy_widget.use_sysem_proxy_radio.setChecked(True)
|
||||||
|
|
||||||
|
# THEN: The other radio buttons should not be checked and the line edits should not be enabled
|
||||||
|
assert proxy_widget.no_proxy_radio.isChecked() is False
|
||||||
|
assert proxy_widget.manual_proxy_radio.isChecked() is False
|
||||||
|
assert proxy_widget.http_edit.isEnabled() is False
|
||||||
|
assert proxy_widget.https_edit.isEnabled() is False
|
||||||
|
assert proxy_widget.username_edit.isEnabled() is False
|
||||||
|
assert proxy_widget.password_edit.isEnabled() is False
|
||||||
|
|
||||||
|
def test_radio_button_exclusivity_manual_proxy(self):
|
||||||
|
"""
|
||||||
|
Test that only one radio button can be checked at a time, and that the line edits are only enabled when the
|
||||||
|
`manual_proxy_radio` is checked
|
||||||
|
"""
|
||||||
|
# GIVEN: An instance of the `openlp.core.common.widgets.widgets.ProxyWidget` with a radio already checked
|
||||||
|
proxy_widget = ProxyWidget()
|
||||||
|
proxy_widget.no_proxy_radio.setChecked(True)
|
||||||
|
|
||||||
|
# WHEN: 'Checking' the `manual_proxy_radio` button
|
||||||
|
proxy_widget.manual_proxy_radio.setChecked(True)
|
||||||
|
|
||||||
|
# THEN: The other radio buttons should not be checked and the line edits should be enabled
|
||||||
|
assert proxy_widget.no_proxy_radio.isChecked() is False
|
||||||
|
assert proxy_widget.use_sysem_proxy_radio.isChecked() is False
|
||||||
|
assert proxy_widget.http_edit.isEnabled() is True
|
||||||
|
assert proxy_widget.https_edit.isEnabled() is True
|
||||||
|
assert proxy_widget.username_edit.isEnabled() is True
|
||||||
|
assert proxy_widget.password_edit.isEnabled() is True
|
||||||
|
|
||||||
|
def test_proxy_widget_load_default_settings(self):
|
||||||
|
"""
|
||||||
|
Test that the default settings are loaded from the config correctly
|
||||||
|
"""
|
||||||
|
# GIVEN: And instance of the widget with default settings
|
||||||
|
proxy_widget = ProxyWidget()
|
||||||
|
|
||||||
|
# WHEN: Calling the `load` method
|
||||||
|
proxy_widget.load()
|
||||||
|
|
||||||
|
# THEN: The widget should be in its default state
|
||||||
|
assert proxy_widget.use_sysem_proxy_radio.isChecked() is True
|
||||||
|
assert proxy_widget.http_edit.text() == ''
|
||||||
|
assert proxy_widget.https_edit.text() == ''
|
||||||
|
assert proxy_widget.username_edit.text() == ''
|
||||||
|
assert proxy_widget.password_edit.text() == ''
|
||||||
|
|
||||||
|
@patch.object(ProxyWidget, 'load')
|
||||||
|
@patch('openlp.core.widgets.widgets.Settings')
|
||||||
|
def test_proxy_widget_save_no_proxy_settings(self, settings_patcher, proxy_widget_load_patcher):
|
||||||
|
"""
|
||||||
|
Test that the settings are saved correctly
|
||||||
|
"""
|
||||||
|
# GIVEN: A Mocked settings instance of the proxy widget with some known values set
|
||||||
|
settings_instance = MagicMock()
|
||||||
|
settings_patcher.return_value = settings_instance
|
||||||
|
proxy_widget = ProxyWidget()
|
||||||
|
proxy_widget.no_proxy_radio.setChecked(True)
|
||||||
|
proxy_widget.http_edit.setText('')
|
||||||
|
proxy_widget.https_edit.setText('')
|
||||||
|
proxy_widget.username_edit.setText('')
|
||||||
|
proxy_widget.password_edit.setText('')
|
||||||
|
|
||||||
|
# WHEN: Calling save
|
||||||
|
proxy_widget.save()
|
||||||
|
|
||||||
|
# THEN: The settings should be set as expected
|
||||||
|
settings_instance.setValue.assert_has_calls(
|
||||||
|
[call('advanced/proxy mode', ProxyMode.NO_PROXY),
|
||||||
|
call('advanced/proxy http', ''),
|
||||||
|
call('advanced/proxy https', ''),
|
||||||
|
call('advanced/proxy username', ''),
|
||||||
|
call('advanced/proxy password', '')])
|
||||||
|
|
||||||
|
@patch.object(ProxyWidget, 'load')
|
||||||
|
@patch('openlp.core.widgets.widgets.Settings')
|
||||||
|
def test_proxy_widget_save_manual_settings(self, settings_patcher, proxy_widget_load_patcher):
|
||||||
|
"""
|
||||||
|
Test that the settings are saved correctly
|
||||||
|
"""
|
||||||
|
# GIVEN: A Mocked and instance of the proxy widget with some known values set
|
||||||
|
settings_instance = MagicMock()
|
||||||
|
settings_patcher.return_value = settings_instance
|
||||||
|
proxy_widget = ProxyWidget()
|
||||||
|
proxy_widget.manual_proxy_radio.setChecked(True)
|
||||||
|
proxy_widget.http_edit.setText('http_proxy_server:port')
|
||||||
|
proxy_widget.https_edit.setText('https_proxy_server:port')
|
||||||
|
proxy_widget.username_edit.setText('username')
|
||||||
|
proxy_widget.password_edit.setText('password')
|
||||||
|
|
||||||
|
# WHEN: Calling save
|
||||||
|
proxy_widget.save()
|
||||||
|
|
||||||
|
# THEN: The settings should be set as expected
|
||||||
|
settings_instance.setValue.assert_has_calls(
|
||||||
|
[call('advanced/proxy mode', ProxyMode.MANUAL_PROXY),
|
||||||
|
call('advanced/proxy http', 'http_proxy_server:port'),
|
||||||
|
call('advanced/proxy https', 'https_proxy_server:port'),
|
||||||
|
call('advanced/proxy username', 'username'),
|
||||||
|
call('advanced/proxy password', 'password')])
|
Loading…
Reference in New Issue
Block a user