Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Changelog
=========

Version 3.0.2
-------------

Bug Fix release

All changes:
https://github.com/Open-MSS/MSS/milestone/55?closed=1

Version 3.0.1
-------------

Expand Down
5 changes: 4 additions & 1 deletion mslib/_tests/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,17 @@
SERVER_CONFIG_FILE = "mss_wms_settings.py"
MSCOLAB_CONFIG_FILE = "mscolab_settings.py"
ROOT_FS = TempFS(identifier="mss{}".format(SHA))
OSFS_URL = ROOT_FS.geturl("", purpose="fs")

ROOT_DIR = ROOT_FS.getsyspath("")

if not ROOT_FS.exists("mss/testdata"):
ROOT_FS.makedirs("mss/testdata")
SERVER_CONFIG_FS = fs.open_fs(fs.path.join(ROOT_DIR, "mss"))
DATA_FS = fs.open_fs(fs.path.join(ROOT_DIR, "mss/testdata"))

MSS_CONFIG_PATH = SERVER_CONFIG_FS.getsyspath("")
MSS_CONFIG_PATH = OSFS_URL
# MSS_CONFIG_PATH = SERVER_CONFIG_FS.getsyspath("") would use a none osfs path
os.environ["MSS_CONFIG_PATH"] = MSS_CONFIG_PATH
SERVER_CONFIG_FILE_PATH = fs.path.join(SERVER_CONFIG_FS.getsyspath(""), SERVER_CONFIG_FILE)

Expand Down
6 changes: 3 additions & 3 deletions mslib/_tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def test_existing_empty_config_file(self):
with fs.open_fs(MSS_CONFIG_PATH) as file_dir:
file_content = file_dir.readtext("mss_settings.json")
assert ":" not in file_content
config_file = fs.path.join(MSS_CONFIG_PATH, "mss_settings.json")
config_file = fs.path.combine(MSS_CONFIG_PATH, "mss_settings.json")
data = utils.config_loader(config_file=config_file)
assert data["num_labels"] == 10
num_labels = utils.config_loader(config_file=config_file, dataset="num_labels")
Expand All @@ -144,7 +144,7 @@ def test_existing_config_file_different_parameters(self):
with fs.open_fs(MSS_CONFIG_PATH) as file_dir:
file_content = file_dir.readtext("mss_settings.json")
assert "num_labels" not in file_content
config_file = fs.path.join(MSS_CONFIG_PATH, "mss_settings.json")
config_file = fs.path.combine(MSS_CONFIG_PATH, "mss_settings.json")
data = utils.config_loader(config_file=config_file)
assert data["num_labels"] == 10
num_labels = utils.config_loader(config_file=config_file, dataset="num_labels")
Expand All @@ -168,7 +168,7 @@ def test_existing_config_file_defined_parameters(self):
with fs.open_fs(MSS_CONFIG_PATH) as file_dir:
file_content = file_dir.readtext("mss_settings.json")
assert "num_labels" in file_content
config_file = fs.path.join(MSS_CONFIG_PATH, "mss_settings.json")
config_file = fs.path.combine(MSS_CONFIG_PATH, "mss_settings.json")
num_labels = utils.config_loader(config_file=config_file, dataset="num_labels")
assert num_labels == 10
# this overwrites the given value
Expand Down
3 changes: 2 additions & 1 deletion mslib/msui/_tests/test_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
See the License for the specific language governing permissions and
limitations under the License.
"""

import pytest
import mock
import os
import fs
Expand Down Expand Up @@ -64,6 +64,7 @@ def test_file_open(self, mockfile):

@mock.patch("mslib.msui.editor.get_open_filename", return_value=sample_file)
def test_file_save_and_quit(self, mockfile):
pytest.skip('needs to be run isolated! With the restart of MSS the config for all other tests is changed')
self.window.file_open()
self.window.path = self.save_file_name
self.window.editor.setPlainText(self.window.editor.toPlainText() + " ")
Expand Down
7 changes: 5 additions & 2 deletions mslib/msui/_tests/test_mscolab.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def test_url_combo(self):
assert self.window.url.count() >= 1

def test_login(self):
pytest.skip("Failing randomly for unknown reasons #870")
self._connect_to_mscolab()
self._login()
# screen shows logout button
Expand All @@ -85,6 +86,7 @@ def test_login(self):
assert self.window.conn is None

def test_disconnect(self):
pytest.skip("Failing randomly for unknown reasons #870")
self._connect_to_mscolab()
QtTest.QTest.mouseClick(self.window.toggleConnectionBtn, QtCore.Qt.LeftButton)
assert self.window.mscolab_server_url is None
Expand Down Expand Up @@ -137,7 +139,6 @@ def test_handle_export(self, mockbox):
return_value=(fs.path.join(mscolab_settings.MSCOLAB_DATA_DIR, 'test_import.ftml'), None))
@mock.patch("PyQt5.QtWidgets.QMessageBox")
def test_import_file(self, mockExport, mockImport, mockMessage):
pytest.skip("See issue #861")
self._connect_to_mscolab()
self._login()
self._activate_project_at_index(0)
Expand Down Expand Up @@ -301,13 +302,15 @@ def test_delete_project_from_list(self):
def _connect_to_mscolab(self):
self.window.url.setEditText(self.url)
QtTest.QTest.mouseClick(self.window.toggleConnectionBtn, QtCore.Qt.LeftButton)
QtTest.QTest.qWait(100)
QtWidgets.QApplication.processEvents()
QtTest.QTest.qWait(500)

def _login(self, emailid="a", password="a"):
self.window.emailid.setText(emailid)
self.window.password.setText(password)
QtTest.QTest.mouseClick(self.window.loginButton, QtCore.Qt.LeftButton)
QtWidgets.QApplication.processEvents()
QtTest.QTest.qWait(500)

@mock.patch("mslib.msui.mscolab.QtWidgets.QErrorMessage.showMessage")
def _create_user(self, username, email, password, mockbox):
Expand Down
20 changes: 20 additions & 0 deletions mslib/msui/_tests/test_mss_pyui.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,33 @@
import sys
import mock
import os
from urllib.request import urlopen
from PyQt5 import QtWidgets, QtTest
from mslib import __version__
from mslib._tests.constants import ROOT_DIR
import mslib.msui.mss_pyui as mss_pyui
from mslib.plugins.io.text import load_from_txt, save_to_txt
from mslib.plugins.io.flitestar import load_from_flitestar


class Test_MSS_AboutDialog():
def setup(self):
self.application = QtWidgets.QApplication(sys.argv)
self.window = mss_pyui.MSS_AboutDialog()

def test_milestone_url(self):
with urlopen(self.window.milestone_url) as f:
text = f.read()
pattern = f'value="is:closed milestone:{__version__[:-1]}"'
assert pattern in text.decode('utf-8')

def teardown(self):
self.window.hide()
QtWidgets.QApplication.processEvents()
self.application.quit()
QtWidgets.QApplication.processEvents()


class Test_MSSSideViewWindow(object):
sample_path = os.path.join(os.path.dirname(__file__), "..", "..", "..", "docs", "samples", "flight-tracks")
save_csv = os.path.join(ROOT_DIR, "example.csv")
Expand Down
2 changes: 1 addition & 1 deletion mslib/msui/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

import os

HOME = os.path.expanduser("~/")
HOME = os.path.expanduser(f"~{os.path.sep}")
MSS_CONFIG_PATH = os.getenv("MSS_CONFIG_PATH", os.path.join(HOME, ".config", "mss"))
if not os.path.exists(MSS_CONFIG_PATH):
os.makedirs(MSS_CONFIG_PATH)
Expand Down
14 changes: 10 additions & 4 deletions mslib/msui/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from mslib.msui.mss_qt import get_open_filename, get_save_filename
from PyQt5 import QtWidgets, QtGui, QtCore, QtPrintSupport
from mslib.msui import constants
from mslib.msui.constants import MSS_CONFIG_PATH
from mslib.msui.constants import MSS_CONFIG_PATH, MSS_SETTINGS
from mslib.msui.icons import icons


Expand All @@ -51,15 +51,19 @@ def __init__(self, parent=None):
# Could also use a QTextEdit and set self.editor.setAcceptRichText(False)
self.editor = QtWidgets.QPlainTextEdit()

# Load mss_settings.json (if already exists)
# Load mss_settings.json (if already exists), change \\ to / so fs can work with it
self.path = constants.CACHED_CONFIG_FILE
if self.path:
if self.path is not None:
self.path = self.path.replace("\\", "/")
dir_name, file_name = fs.path.split(self.path)
with fs.open_fs(dir_name) as _fs:
if _fs.exists(file_name):
self.file_content = _fs.readtext(file_name)
self.editor.setPlainText(self.file_content)
self.update_title()
else:
self.path = MSS_SETTINGS
self.path = self.path.replace("\\", "/")
self.last_saved = self.editor.toPlainText()

# Setup the QTextEdit editor configuration
Expand Down Expand Up @@ -201,7 +205,6 @@ def file_save_and_quit(self):
if self.check_modified():
if self.check_json():
self._save_to_path(self.path)

ret = QtWidgets.QMessageBox.warning(
self, self.tr("Mission Support System"),
self.tr("Do you want to restart the application?\n"
Expand All @@ -215,6 +218,8 @@ def file_save_and_quit(self):
def file_saveas(self):
if self.check_json():
default_filename = constants.CACHED_CONFIG_FILE
if default_filename is None:
default_filename = MSS_SETTINGS
path = get_save_filename(
self, "Save file", default_filename, "Text documents (*.json)")
# If dialog is cancelled, will return ''
Expand All @@ -229,6 +234,7 @@ def _save_to_path(self, filename):
with fs.open_fs(dir_name) as _fs:
_fs.writetext(file_name, text)
self.update_title()
constants.CACHED_CONFIG_FILE = self.path

def file_print(self):
dlg = QtPrintSupport.QPrintDialog()
Expand Down
68 changes: 58 additions & 10 deletions mslib/msui/mscolab.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,14 @@
See the License for the specific language governing permissions and
limitations under the License.
"""
import os
import sys
import json
import logging
import types
import fs
import requests
import re
from fs import open_fs
from werkzeug.urls import url_join

Expand All @@ -54,7 +57,6 @@
from mslib.utils import load_settings_qsettings, save_settings_qsettings, dropEvent, dragEnterEvent, show_popup
from mslib.msui import constants
from mslib.utils import config_loader
from mslib.msui import MissionSupportSystemDefaultConfig as mss_default

MSCOLAB_URL_LIST = QtGui.QStandardItemModel()

Expand All @@ -73,7 +75,8 @@ class MSSMscolabWindow(QtWidgets.QMainWindow, ui.Ui_MSSMscolabWindow):
identifier = None
viewCloses = QtCore.pyqtSignal(name="viewCloses")

def __init__(self, parent=None, data_dir=mss_default.mss_dir, mscolab_server_url=mss_default.mscolab_server_url):
# ToDo refactor tests, mscolab_server_url not used
def __init__(self, parent=None, data_dir=None, mscolab_server_url=None):
"""
Set up user interface
"""
Expand Down Expand Up @@ -135,7 +138,11 @@ def __init__(self, parent=None, data_dir=mss_default.mss_dir, mscolab_server_url
# Mscolab help dialog
self.help_dialog = None
# set data dir, uri
self.data_dir = data_dir
if data_dir is None:
self.data_dir = config_loader(dataset="mss_dir")
else:
self.data_dir = data_dir
self.create_dir()
self.mscolab_server_url = None
self.disable_action_buttons()
# disabling login, add user button. they are enabled when url is connected
Expand All @@ -153,6 +160,24 @@ def __init__(self, parent=None, data_dir=mss_default.mss_dir, mscolab_server_url
self.settings = load_settings_qsettings(
'mscolab', default_settings={'auth': {}, 'server_settings': {}})

def create_dir(self):
# ToDo this needs to be done earlier
if '://' in self.data_dir:
try:
_ = fs.open_fs(self.data_dir)
except fs.errors.CreateFailed:
logging.error(f'Make sure that the FS url "{self.data_dir}" exists')
show_popup(self, "Error", f'FS Url: "{self.data_dir}" does not exist!')
sys.exit()
except fs.opener.errors.UnsupportedProtocol:
logging.error(f'FS url "{self.data_dir}" not supported')
show_popup(self, "Error", f'FS Url: "{self.data_dir}" not supported!')
sys.exit()
else:
_dir = os.path.expanduser(self.data_dir)
if not os.path.exists(_dir):
os.makedirs(_dir)

def disconnect_handler(self):
self.logout()
self.status.setText("Status: disconnected")
Expand All @@ -163,8 +188,11 @@ def disconnect_handler(self):
self.addUser.setEnabled(False)
self.emailid.setEnabled(False)
self.password.setEnabled(False)
self.emailid.textChanged[str].disconnect(self.text_changed)
self.password.textChanged[str].disconnect(self.text_changed)
# toggle to connect button
self.toggleConnectionBtn.setText('Connect')
self.toggleConnectionBtn.clicked.disconnect(self.disconnect_handler)
self.toggleConnectionBtn.clicked.connect(self.connect_handler)
self.url.setEnabled(True)
# set mscolab_server_url to None
Expand Down Expand Up @@ -195,15 +223,20 @@ def connect_handler(self):
self.password.textChanged[str].connect(self.text_changed)
# toggle to disconnect button
self.toggleConnectionBtn.setText('Disconnect')
self.toggleConnectionBtn.clicked.disconnect(self.connect_handler)
self.toggleConnectionBtn.clicked.connect(self.disconnect_handler)
self.url.setEnabled(False)
if self.mscolab_server_url not in self.settings["server_settings"].keys():
self.settings["server_settings"].update({self.mscolab_server_url: {}})
save_settings_qsettings('mscolab', self.settings)
self.emailid.setEnabled(True)
self.password.setEnabled(True)
self.emailid.setText(config_loader(dataset="MSCOLAB_mailid"))
self.password.setText(config_loader(dataset="MSCOLAB_password"))
emailid = config_loader(dataset="MSCOLAB_mailid")
self.emailid.setText(emailid)
password = config_loader(dataset="MSCOLAB_password")
self.password.setText(password)
if len(emailid) > 0 and len(password) > 0:
self.loginButton.setEnabled(True)
else:
show_popup(self, "Error", "Some unexpected error occurred. Please try again.")
except requests.exceptions.ConnectionError:
Expand Down Expand Up @@ -340,6 +373,11 @@ def add_project(self):
self.error_dialog = QtWidgets.QErrorMessage()
self.error_dialog.showMessage('Description can\'t be empty')
return
# regex checks if the whole path from beginning to end only contains alphanumerical characters or _ and -
elif not re.match("^[a-zA-Z0-9_-]*$", path):
self.error_dialog = QtWidgets.QErrorMessage()
self.error_dialog.showMessage('Path can\'t contain spaces or special characters')
return

data = {
"token": self.token,
Expand Down Expand Up @@ -510,8 +548,10 @@ def handle_work_locally_toggle(self):
if self.version_window is not None:
self.version_window.close()
self.create_local_project_file()
self.local_ftml_file = fs.path.join(self.data_dir, 'local_mscolab_data',
self.user['username'], self.active_project_name, 'mscolab_project.ftml')
self.local_ftml_file = fs.path.combine(self.data_dir,
fs.path.join('local_mscolab_data',
self.user['username'], self.active_project_name,
'mscolab_project.ftml'))
self.helperTextLabel.setText(
self.tr("Working On: Local File. Your changes are only available to you."
"To save your changes with everyone, use the \"Save to Server\" button."))
Expand Down Expand Up @@ -549,15 +589,23 @@ def authorize(self):
s.auth = (auth[0], auth[1])
s.headers.update({'x-test': 'true'})
url = self.mscolab_server_url + '/token'
r = s.post(url, data=data)
try:
r = s.post(url, data=data)
except requests.exceptions.ConnectionError as ex:
logging.error("unexpected error: %s %s %s", type(ex), url, ex)
# popup that Failed to establish a connection
self.error_dialog = QtWidgets.QErrorMessage()
self.error_dialog.showMessage('Failed to establish a new connection'
f' to "{self.mscolab_server_url}". Try in a moment again.')
return
if r.status_code == 401:
r = self.authenticate(data, r, url)
if r.status_code == 200 and not r.text == "False":
constants.MSC_LOGIN_CACHE[self.mscolab_server_url] = (auth[0], auth[1])
else:
self.error_dialog = QtWidgets.QErrorMessage()
self.error_dialog.showMessage('Oh no, server authentication were incorrect.')
if r.text == "False":
if r.text == "False" or r.text == "Unauthorized Access":
# popup that has wrong credentials
self.error_dialog = QtWidgets.QErrorMessage()
self.error_dialog.showMessage('Oh no, your credentials were incorrect.')
Expand Down Expand Up @@ -636,7 +684,7 @@ def add_projects_to_ui(self, projects):
self.listProjects.itemActivated.connect(self.set_active_pid)

def force_close_view_windows(self):
for window in self.active_windows:
for window in self.active_windows[:]:
window.handle_force_close()
self.active_windows = []

Expand Down
Loading