Skip to content
This repository has been archived by the owner on Jun 6, 2022. It is now read-only.

Commit

Permalink
Finishing up docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
pocc committed Aug 22, 2018
1 parent c169e94 commit dd05c8b
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 67 deletions.
10 changes: 8 additions & 2 deletions src/gui/login_dialog.py
Expand Up @@ -32,18 +32,24 @@ class LoginDialog(QDialog):
"""This class provides dialog GUI elements.
Attributes:
browser (MechanicalSoup): A browser in which to store user credentials.
----
Please consider moving the brunt of the __init__ UI content to its
own file.
TODO: Convert the other attributes to a dict
"""
# Telling PyCharm linter not to (incorrectly) inspect PyQt function args
# noinspection PyArgumentList
def __init__(self):
"""Create UI vars necessary for login window to be shown."""
super(LoginDialog, self).__init__()
self.setModal(True) # Make the login window prevent program usage

self.browser = DataScraper()

# LOGIN WINDOW UI SETUP
self.setModal(True) # Make the login window prevent program usage
self.meraki_img = QLabel('<a href=https://meraki.cisco.com/products/'
'wireless#mr-new>MR advertisement</a>')
self.meraki_img.setOpenExternalLinks(True)
Expand Down
44 changes: 17 additions & 27 deletions src/gui/main_window.py
Expand Up @@ -15,7 +15,6 @@

"""Main Window is the controlling class for the GUI."""
import sys
from os import getcwd

from PyQt5.QtWidgets import QMainWindow

Expand All @@ -36,37 +35,30 @@ class MainWindow(QMainWindow):
"""Main Window is the controlling class for the GUI.
Attributes:
TODO Missing(missing):
menu_widget (MenuBars): Used to tie the menu bars to the MainWindow
browser (DataScraper): Browser used to store user credentials
tray_icon = SystrayIcon(self)
main_window_ui (MainWindowUi): Class to tie UI to Main Window (while
being in a different file for clarity).
"""
# Telling PyCharm linter not to (incorrectly) inspect PyQt function args
# noinspection PyArgumentList
def __init__(self):
super(MainWindow, self).__init__()

if DEBUG:
print("Main Window")

# If there's a duplicate instance, close this one
if is_duplicate_application('merlink'):
show_error_dialog('ERROR: You already have a running merlink '
'instance!'
'\nThis application will now close.')
'instance!\nThis application will now close.')
self.close() # In lieu of sys.exit(app.exec_())

# Passing the self.menuBar() variable is critical for menu bars
self.browser = DataScraper()

# Tie the menu bars, tray_icon, and main window UI to this object.
self.menu_widget = MenuBars(self.menuBar())
self.menu_widget.generate_menu_bars()

# Variables
self.browser = DataScraper()
self.platform = sys.platform
self.network_admin_only = False
# We use cwd in multiple places, so fetch current working dir once
self.cwd = getcwd()
self.tray_icon = SystrayIcon(self)
self.is_connected = False

self.main_window_ui = MainWindowUi(self)

self.show()

def show_main_menu(self):
Expand All @@ -89,7 +81,7 @@ def show_main_menu(self):
current_org = self.browser.get_current_org()
self.org_dropdown.addItems(org_list)
# Get the data we need and remove the cruft we don't
self.browser.scrape_org_networks()
self.browser.scrape_networks_by_org()
self.status.showMessage("Status: Fetching networks in " +
current_org + "...")
# Remove all elements from the network UI dropdown
Expand Down Expand Up @@ -147,7 +139,7 @@ def change_organization(self):
print("we are getting new info for " + selected_org +
" at index" + str(selected_org_index))
self.browser.set_current_org(selected_org_index)
self.browser.scrape_org_networks()
self.browser.scrape_networks_by_org()

self.refresh_network_dropdown()
self.status.showMessage("Status: Select network")
Expand Down Expand Up @@ -237,14 +229,14 @@ def setup_vpn(self):
# Create VPN connection
vpn_data = [
vpn_name,
self.browser.current_ddns,
self.browser.psk,
self.browser.vpn_vars['current_ddns'],
self.browser.vpn_vars['psk'],
username,
password
]
connection = VpnConnection(vpn_data)

if self.platform == 'win32':
if sys.platform == 'win32':
windows_options = [
DEBUG,
self.dns_suffix_txtbox.text(),
Expand All @@ -256,13 +248,13 @@ def setup_vpn(self):
successful_attempt = \
connection.attempt_windows_vpn(windows_options)

elif self.platform == 'darwin':
elif sys.platform == 'darwin':
macos_options = []
successful_attempt = \
connection.attempt_macos_vpn(macos_options)

# linux, linux2 are valid for linux distros
elif self.platform.startswith('linux'):
elif sys.platform.startswith('linux'):
linux_options = []
successful_attempt = \
connection.attempt_linux_vpn(linux_options)
Expand All @@ -277,7 +269,6 @@ def setup_vpn(self):

def communicate_vpn_success(self):
"""Let the user know that they are connected."""
self.is_connected = True
self.status.showMessage('Status: Connected')
vpn_success_dialog()

Expand All @@ -288,7 +279,6 @@ def communicate_vpn_success(self):

def communicate_vpn_failure(self):
"""Let the user know tha the VPN connection failed."""
self.is_connected = False
self.status.showMessage('Status: Connection Failed')
self.error_dialog("Connection Failed")
self.tray_icon.set_vpn_failure()
Expand Down
12 changes: 11 additions & 1 deletion src/gui/main_window_ui.py
Expand Up @@ -29,7 +29,17 @@


class MainWindowUi:
"""Taking in 'app', which is the MainWindow object"""
"""Takes a MainWindow object and then decorates it like a cake.
This file exists to take much of the UI content of the MainWindow class
so that the MainWindow class can be cleaner. This is in lieu of having
created the UI files in Qt Designer, converted them to pyuic, and then
never touched the UI files again (not a route I chose to go).
Attributes:
app (MainWindow): The main window object that this class decorates.
"""
# Telling PyCharm linter not to (incorrectly) inspect PyQt function args
# noinspection PyArgumentList
def __init__(self, app):
Expand Down
12 changes: 11 additions & 1 deletion src/gui/systray.py
Expand Up @@ -22,8 +22,18 @@
from src.modules.os_utils import pyinstaller_path
from src.modules.os_utils import open_vpnsettings


class SystrayIcon:
"""Taking in 'app', which is the MainWindow object"""
"""This class manages the system tray icon of the main program.
It will only trigger after login.
Args:
app (QMainWindow): Set to MainWindow object (required binding for Qt)
tray_icon (QSystemTrayIcon): System Tray object that has all of the
functionality that this class requires.
"""

def __init__(self, app):
# Init QSystemTrayIcon
# Set the Window and Tray Icons
Expand Down
2 changes: 1 addition & 1 deletion src/modules/controller.py
Expand Up @@ -32,7 +32,7 @@ class Controller:
Attributes:
interface (MainWindow | MainCli): Calls interface-dependent functions
(this is a primitive form of overloading).
(this is a primitive form of overloading).
app (QApplication): Required for the Qt program flow, not used for CLI
"""
Expand Down
67 changes: 42 additions & 25 deletions src/modules/dashboard_browser.py
Expand Up @@ -30,6 +30,30 @@ class DataScraper:
password (string): User-entered password, used to login
browser (MechanicalSoup): Main browser object to send data to dashboard
----
vpn_vars (dict): List of VPN variables (does the browser need access
to this?)
org_links (dict): A dict of org names and their links
org_list (list): A list of orgs (= org_links.keys())
===> Probably want to get rid of this and use the equivalent instead.
network_list (list): List of netwoks?????
base_url_list (list): List of base urls?????
org_qty (int): Number of organizations someone has access to. Once
determined, it should be invariant.
current_org (string): Name of the org that is currently selecetd.
current_org_index (int): Org index (0 = select option), so start from 1.
network_admin_only (bool): Does the admin have no org-level access?
current_network (string): Name of the current network
fw_status_text (string): Text of the appliance status page
client_vpn_url (string): Client VPN url pivoted from current network
client_vpn_text (string): Text of the client vpn page
client_vpn_soup (BeautifulSoup): Soup object of the client VPN page
TODO: Convert the other attributes to a dict
"""
def __init__(self):
Expand All @@ -47,53 +71,46 @@ def __init__(self):
'AppleWebKit/601.6 (KHTML, like Gecko) '
'NF/4.0.0.5.9 NintendoBrowser/5.1.0.13341',
)
# Set tfa_success to false
self.tfa_success = False

# By default, you have access to 0 orgs
self.org_qty = 0
# Initialize organization dictionary {Name: Link} and
# list for easier access. org_list is org_links.keys()
self.org_links = {}
self.org_list = []
self.network_list = []
self.base_url_list = []
self.current_org = 'Org Placeholder' # Org name placeholder

self.org_qty = 0
self.current_org = 'Org Placeholder'
self.current_org_index = 0 # Default to first organization
self.network_admin_only = False # Most admins are org admins

# VPN VARS: Powershell Variables set to defaults
self.current_ddns = '-' # set to default hyphen char as a failsafe
# Expected behavior is to have full-tunnel by default
self.split_tunnel = False
self.remember_credential = False
# If it's set to '', then powershell will skip reading that parameter.
self.DnsSuffix = '-'
# Powershell default for not disconnecting until after x seconds
self.IdleDisconnectSeconds = 0
self.UseWinlogonCredential = False
self.vpn_vars = {
'current_ddns': '-',
'psk': '',
'current_primary_ip': '',

'split_tunnel': False,
'remember_credential': False,
'DnsSuffix': '-',
'IdleDisconnectSeconds': 0, # Powershell default
'UseWinlogonCredential': False,
}

self.is_connected = False
self.username = ''
self.password = ''

self.current_network = ''
self.fw_status_text = ''
self.client_vpn_url = ''
self.client_vpn_text = ''
self.client_vpn_soup = ''
self.psk = ''

self.fw_status_text = ''
self.current_primary_ip = ''

def get_url(self):
"""Get the current URL"""
print("browser url in get_url" + str(self.browser.get_url()))
return self.browser.get_url()

def get_tfa_success(self):
"""Get the TFA success bool"""
return self.tfa_success

# Return browser with any username, password, and cookies with it
def get_browser(self):
"""Get the MechanicalSoup object with associated login cookies."""
Expand Down Expand Up @@ -399,8 +416,8 @@ def scrape_ddns_and_ip(self, current_network_index):
ddns_value_start = self.fw_status_text.find("dynamic_dns_name")+19
ddns_value_end = self.fw_status_text[ddns_value_start:].find('\"') \
+ ddns_value_start
self.current_ddns = self.fw_status_text[ddns_value_start:
ddns_value_end]
self.vpn_vars['current_ddns'] = \
self.fw_status_text[ddns_value_start:ddns_value_end]

# Primary will always come first, so using find should
# find it's IP address, even if there's a warm spare
Expand Down
20 changes: 10 additions & 10 deletions src/modules/vpn_connection.py
Expand Up @@ -61,12 +61,12 @@ def attempt_windows_vpn(self, vpn_options):
* Arguments sent to powershell MUST BE STRINGS
* Each argument cannot be the empty string or null or PS will think
there's no param there!!!
there's no param there!!!
* Last 3 ps params are bools converted to ints (0/1) converted to
strings. It's easy to force convert '0' and '1' to ints on
powershell side.
strings. It's easy to force convert '0' and '1' to ints on
powershell side.
* Setting execution policy to unrestricted is necessary so that we
can access VPN functions
can access VPN functions
* Email CANNOT have spaces, but password can.
"""

Expand Down Expand Up @@ -139,12 +139,12 @@ def attempt_macos_vpn(self, vpn_options):
def attempt_linux_vpn(self, vpn_options):
"""Attempt to connect on linux.
sudo required to create a connection with nmcli
pkexec is built into latest Fedora, Debian, Ubuntu.
'pkexec <cmd>' correctly asks in GUI on Debian, Ubuntu but in
terminal on Fedora
pkexec is PolicyKit, which is the preferred means of asking for
permission on LSB
* sudo required to create a connection with nmcli
* pkexec is built into latest Fedora, Debian, Ubuntu.
* 'pkexec <cmd>' correctly asks in GUI on Debian, Ubuntu but in
terminal on Fedora
* pkexec is PolicyKit, which is the preferred means of asking for
permission on LSB
"""

self.vpn_options = vpn_options
Expand Down

0 comments on commit dd05c8b

Please sign in to comment.