Skip to content

Commit

Permalink
Merge pull request #3 from SairusCZ/add_profile_settings
Browse files Browse the repository at this point in the history
Add profile settings
  • Loading branch information
bpozdena authored Jan 30, 2022
2 parents 26e3b70 + e652c95 commit 17bf8e3
Show file tree
Hide file tree
Showing 12 changed files with 378 additions and 94 deletions.
143 changes: 127 additions & 16 deletions OneDriveGUI/OneDriveGUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import re
import subprocess
import sys
import time
from configparser import ConfigParser

from PySide6.QtCore import QThread, QTimer, QUrl, Signal, QFileInfo, Qt
Expand Down Expand Up @@ -54,6 +55,7 @@ def __init__(self):
self.listWidget_profiles.itemSelectionChanged.connect(self.switch_account_settings_page)
self.pushButton_open_create.clicked.connect(self.create_new_profile_window)
self.pushButton_open_import.clicked.connect(self.import_profile_window)
self.pushButton_remove.clicked.connect(self.remove_profile)
self.show()

def switch_account_settings_page(self):
Expand Down Expand Up @@ -84,9 +86,34 @@ def import_profile_window(self):
self.import_ui.pushButton_import.clicked.connect(self.import_profile)

# Hide window once account is created
self.import_ui.pushButton_import.clicked.connect(self.import_window.hide)
self.import_ui.pushButton_import.clicked.connect(self.import_window.hide)


def remove_profile(self):
# Remove profile from settings window.
selected_profile_name = self.listWidget_profiles.currentItem().text()
selected_profile_index = self.listWidget_profiles.currentRow()
selected_profile_widget = self.stackedLayout.currentWidget()
self.listWidget_profiles.takeItem(selected_profile_index)
self.stackedLayout.removeWidget(selected_profile_widget)

# Remove profile from main window.
combo_box_index = main_window.comboBox.findText(selected_profile_name)
main_window.comboBox.removeItem(combo_box_index)
main_window.profile_status_pages.pop(selected_profile_name, None)
global_config.pop(selected_profile_name, None)
print(global_config)

# Load existing user profiles and remove the new profile.
_profiles = ConfigParser()
_profiles.read(PROFILES_FILE)
_profiles.remove_section(selected_profile_name)

# Save the new profile.
with open(PROFILES_FILE, 'w') as profilefile:
_profiles.write(profilefile)


def create_profile(self):
"""
Creates new profile and loads default settings.
Expand Down Expand Up @@ -114,19 +141,28 @@ def create_profile(self):
_profiles.read(PROFILES_FILE)
_profiles[profile_name] = new_profile[profile_name]

with open(PROFILES_FILE, 'w') as configfile:
_profiles.write(configfile)
# Create profile config file if it does not exist.
profiles_dir = re.search(r"(.+)/profiles$", PROFILES_FILE).group(1)
if not os.path.exists(profiles_dir):
os.makedirs(profiles_dir)

# Save the new profile.
with open(PROFILES_FILE, 'w') as profilefile:
_profiles.write(profilefile)


# Append default OD config
new_profile[profile_name].update(default_od_config)

# Configure sync directory
new_profile[profile_name]['onedrive']['sync_dir'] = sync_dir
new_profile[profile_name]['onedrive']['sync_dir'] = f'"{sync_dir}"'

# Append new profile into running global profile
global_config.update(new_profile)

# Automatically save global config to prevent loss if user does not press 'Save' button.
save_global_config()

# Add Setting page widget for new profile
self.listWidget_profiles.addItem(profile_name)
self.page = ProfileSettingsPage(profile_name)
Expand All @@ -135,8 +171,10 @@ def create_profile(self):
# Add status page widget for new profile
main_window.comboBox.addItem(profile_name)
main_window.profile_status_pages[profile_name] = ProfileStatusPage(profile_name)
main_window.stackedLayout.addWidget(main_window.profile_status_pages[profile_name])
main_window.stackedLayout.addWidget(main_window.profile_status_pages[profile_name])

# Hide "Create profile" push button from main windows.
main_window.pushButton_new_profile.hide()



Expand Down Expand Up @@ -173,6 +211,12 @@ def import_profile(self):
_profiles.read(PROFILES_FILE)
_profiles[profile_name] = new_profile[profile_name]

# Create profile config file if it does not exist.
profiles_dir = re.search(r"(.+)/profiles$", PROFILES_FILE).group(1)
if not os.path.exists(profiles_dir):
os.makedirs(profiles_dir)

# Save the new profile.
with open(PROFILES_FILE, 'w') as configfile:
_profiles.write(configfile)

Expand All @@ -191,7 +235,8 @@ def import_profile(self):
self.page = ProfileSettingsPage(profile_name)
self.stackedLayout.addWidget(self.page)


# Hide "Create profile" push button from main windows.
main_window.pushButton_new_profile.hide()


class ProfileStatusPage(QWidget, Ui_status_page):
Expand All @@ -204,6 +249,15 @@ def __init__(self, profile):
# Show selected profile name
self.label_4.setText(profile)

# Temporary start/stop buttons
self.toolButton_start.clicked.connect(lambda: main_window.start_onedrive_monitor(profile))
self.toolButton_stop.clicked.connect(lambda: main_window.workers[profile].stop_worker())
# self.toolButton_stop.clicked.connect(lambda: main_window.workers[profile].exit())
# self.toolButton_stop.clicked.connect(lambda: main_window.workers[profile].quit())
# self.toolButton_stop.clicked.connect(lambda: main_window.workers[profile].terminate())
# self.toolButton_stop.clicked.connect(lambda: main_window.workers.pop(profile, None))


# # Open Settings window
self.pushButton_settings.clicked.connect(self.show_settings_window)

Expand All @@ -215,6 +269,9 @@ def show_settings_window(self):
self.settings_window = SettingsWindow()
self.settings_window.show()

# def stop_worker(self, profile):
# main_window.workers[profile].onedrive_process.kill()


class ProfileSettingsPage(QWidget, Ui_profile_settings):
def __init__(self, profile):
Expand Down Expand Up @@ -392,6 +449,16 @@ def __init__(self, profile):
self.spinBox_min_notify_changes.setValue(int(self.temp_profile_config['min_notify_changes'].strip('"')))
self.spinBox_min_notify_changes.valueChanged.connect(self.set_spin_box_value)

#
# Account tab
#
self.config_file = global_config[self.profile]['config_file'].strip('"')
self.config_dir = re.search(r"(.+)/.+$", self.config_file).group(1)

self.pushButton_login.clicked.connect(lambda: main_window.show_login(self.profile))
self.pushButton_logout.clicked.connect(lambda: os.system(f"onedrive --confdir='{self.config_dir}' --logout"))
self.pushButton_logout.clicked.connect(lambda: print(f"Profile {self.profile} has been logged out."))

#
# Buttons
#
Expand Down Expand Up @@ -523,7 +590,7 @@ def hide_progress_bar(self, transfer_status: bool):


class WorkerThread(QThread):
update_credentials = Signal()
update_credentials = Signal(str)
update_progress = Signal(dict)
update_progress_new = Signal(dict, str)
trigger_resync = Signal()
Expand All @@ -540,6 +607,23 @@ def __init__(self, profile):
# print(f"command is: {self._command}")
self._profile_name = profile

def stop_worker(self):
print(f"[{self._profile_name}] Waiting for worker to finish...")
while self.onedrive_process.poll() is None:
self.onedrive_process.kill()
time.sleep(1)

print(f"[{self._profile_name}] Quiting thread")
self.quit()
self.wait()
print(f"[{self._profile_name}] Removing thread info")
main_window.workers.pop(self._profile_name, None)
print(f"Remaining running workers: {main_window.workers}")





def run(self, resync=False):
matches = ['Downloading file', 'Downloading new file', 'Uploading file', 'Uploading new file',
'Uploading modified file', 'Downloading modified file']
Expand All @@ -562,7 +646,7 @@ def run(self, resync=False):

if 'Authorize this app visiting' in stdout:
self.onedrive_process.kill()
self.update_credentials.emit()
self.update_credentials.emit(self._profile_name)

elif any(x in stdout for x in matches): # capture file uploads and downloads
# self.tray.setIcon(QIcon("resources/images/icons8-cloud-sync-40_2.png"))
Expand Down Expand Up @@ -640,6 +724,8 @@ def run(self, resync=False):
print('@@ERROR' + stderr)




class MainWindow(QMainWindow, Ui_MainWindow):

def __init__(self):
Expand All @@ -649,9 +735,19 @@ def __init__(self):
self.setupUi(self)
self.setWindowIcon(QIcon("resources/images/icons8-clouds-48.png"))

if len(global_config) == 0:
# self.pushButton_new_profile.clicked.connect(self.show_settings_window)
# self.pushButton_new_profile.show()
self.show_settings_window()

# else:
self.pushButton_new_profile.hide()

#
# Menu
#

self.menubar.hide()
# Update OneDrive Status
self.actionRefresh_Service_Status.triggered.connect(lambda: self.onedrive_process_status())

Expand Down Expand Up @@ -712,6 +808,10 @@ def __init__(self):
else:
self.tray = None

def show_settings_window(self):
self.settings_window = SettingsWindow()
self.settings_window.show()

def switch_account_status_page(self):
self.stackedLayout.setCurrentIndex(self.comboBox.currentIndex())

Expand Down Expand Up @@ -743,12 +843,17 @@ def onedrive_sync_status(self):

def start_onedrive_monitor(self, profile_name):
# for profile in global_config:
self.workers[profile_name] = WorkerThread(profile_name)
self.workers[profile_name].start()

if profile_name not in self.workers:
self.workers[profile_name] = WorkerThread(profile_name)
self.workers[profile_name].start()
else:
print(f"Worker for profile {profile_name} is already running. Please stop it first.")
print(f"Running workers: {main_window.workers}")

# self.worker = WorkerThread()
# self.worker.start()
# self.worker.update_credentials.connect(self.show_login)
self.workers[profile_name].update_credentials.connect(self.show_login)
# self.worker.update_progress.connect(self.event_update_progress)
# self.worker.trigger_resync.connect(self.show_login)
self.workers[profile_name].update_progress_new.connect(self.event_update_progress_new)
Expand Down Expand Up @@ -795,7 +900,7 @@ def event_update_progress_new(self, data, profile):

print(data)
file_path = f'{_sync_dir}' + "/" + data['file_path']
absolute_path = QFileInfo(file_path).absolutePath()
absolute_path = QFileInfo(file_path).absolutePath().replace(' ','%20')
parent_dir = re.search(r".+/([^/]+)/.+$", file_path)
file_size = QFileInfo(file_path).size()
file_size_human = humanize_file_size(file_size)
Expand Down Expand Up @@ -888,14 +993,17 @@ def event_update_progress_new(self, data, profile):
self.profile_status_pages[profile].listWidget.setItemWidget(myQListWidgetItem, myQCustomQWidget)


def show_login(self):
def show_login(self, profile):
# Show login window
self.window1 = QWidget()
self.window1.setWindowIcon(QIcon("resources/images/icons8-clouds-48.png"))
self.lw = Ui_LoginWindow()
self.lw.setupUi(self.window1)
self.window1.show()

self.config_file = global_config[profile]['config_file'].strip('"')
self.config_dir = re.search(r"(.+)/.+$", self.config_file).group(1)

# use static URL for now. TODO: use auth files in the future
url = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=d50ca740-c83f-4d1b-b616' \
'-12c519384f0c&scope=Files.ReadWrite%20Files.ReadWrite.all%20Sites.Read.All%20Sites.ReadWrite.All' \
Expand All @@ -904,18 +1012,21 @@ def show_login(self):
self.lw.loginFrame.setUrl(QUrl(url))

# Wait for user to login and obtain response URL
self.lw.loginFrame.urlChanged.connect(lambda: self.get_response_url(self.lw.loginFrame.url().toString()))
self.lw.loginFrame.urlChanged.connect(lambda: self.get_response_url(self.lw.loginFrame.url().toString(), self.config_dir, profile))

def get_response_url(self, response_url):
def get_response_url(self, response_url, config_dir, profile):
# Get response URL from OneDrive OAuth2
if 'nativeclient?code=' in response_url:
os.system(f'onedrive --auth-response "{response_url}"')
print(f'onedrive --confdir="{config_dir}" --auth-response "{response_url}"')
os.system(f'onedrive --confdir="{config_dir}" --auth-response "{response_url}"')
print("Login performed")
self.window1.hide()
main_window.workers[profile].onedrive_process.kill()
else:
pass



def read_config(config_file):
with open(config_file, 'r') as f:
config_string = '[onedrive]\n' + f.read()
Expand Down
3 changes: 1 addition & 2 deletions OneDriveGUI/resources/default_config
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ remove_source_files = "false"
skip_dir_strict_match = "false"
application_id = ""
resync = "false"
resync_auth = "false"
bypass_data_preservation = "false"
azure_ad_endpoint = ""
azure_tenant_id = "common"
Expand All @@ -42,4 +41,4 @@ webhook_public_url = ""
webhook_listening_host = ""
webhook_listening_port = "8888"
webhook_expiration_interval = "86400"
webhook_renewal_interval = "43200"
webhook_renewal_interval = "43200"
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 17bf8e3

Please sign in to comment.