def preview_change(self, current_item, previous_item): font = QtGui.QFont() if previous_item is not None: previous_item.setFont(font) if current_item is None: self.changePreviewTable.setModel(None) self.deleteVersionNameBtn.setVisible(False) self.toggle_version_buttons(False) return font.setBold(True) current_item.setFont(font) data = {"token": self.token, "ch_id": current_item.id} url = url_join(self.mscolab_server_url, 'get_change_content') res = requests.get(url, data=data) if res.text != "False": res = res.json() waypoint_model = WaypointsTableModel(xml_content=res["content"]) self.changePreviewTable.setModel(waypoint_model) if current_item.version_name is not None: self.deleteVersionNameBtn.setVisible(True) else: self.deleteVersionNameBtn.setVisible(False) self.toggle_version_buttons(True) else: show_popup(self, "Error", "Session expired, new login required")
def load_all_changes(self): """ get changes from api, clear listwidget, render them to ui """ data = {"token": self.token, "p_id": self.p_id} named_version_only = None if self.versionFilterCB.currentIndex() == 0: named_version_only = True query_string = url_encode({"named_version": named_version_only}) url_path = f'get_all_changes?{query_string}' url = url_join(self.mscolab_server_url, url_path) r = requests.get(url, data=data) if r.text != "False": changes = json.loads(r.text)["changes"] self.changes.clear() for change in changes: created_at = datetime.strptime(change["created_at"], "%Y-%m-%d, %H:%M:%S") local_time = utc_to_local_datetime(created_at) date = local_time.strftime('%d/%m/%Y') time = local_time.strftime('%I:%M %p') item_text = f'{change["username"]} made change on {date} at {time}' if change["version_name"] is not None: item_text = f'{change["version_name"]}\n{item_text}' item = QtWidgets.QListWidgetItem(item_text, parent=self.changes) item.id = change["id"] item.version_name = change["version_name"] self.changes.addItem(item) else: show_popup(self, "Error", "Session expired, new login required")
def send_message(self): """ send message through connection """ if self.attachment is None: reply_id = -1 if self.active_message_reply is not None: reply_id = self.active_message_reply.id message_text = self.messageText.toPlainText() if message_text == "": return message_text = message_text.strip() self.conn.send_message(message_text, self.p_id, reply_id) else: files = {"file": open(self.attachment, 'rb')} data = { "token": self.token, "p_id": self.p_id, "message_type": int(self.attachment_type) } url = url_join(self.mscolab_server_url, 'message_attachment') try: requests.post(url, data=data, files=files) except requests.exceptions.ConnectionError: show_popup(self, "Error", "File size too large") self.send_message_state()
def handle_permissions_updated(self, u_id): if self.user["id"] == u_id: return show_popup(self, 'Alert', 'The permissions for this project were updated! The window is going to refresh.', 1) self.load_users_without_permission() self.load_users_with_permission()
def add_selected_users(self): selected_userids = self.get_selected_userids(self.addUsersTable, self.addUsers) if len(selected_userids) == 0: return selected_access_level = str(self.addUsersPermission.currentText()) data = { "token": self.token, "p_id": self.p_id, "selected_userids": json.dumps(selected_userids), "selected_access_level": selected_access_level } url = url_join(self.mscolab_server_url, "add_bulk_permissions") res = requests.post(url, data=data) if res.text != "False": res = res.json() if res["success"]: # TODO: Do we need a success popup? self.load_users_without_permission() self.load_users_with_permission() else: show_popup(self, "Error", res["message"]) else: show_popup(self, "Error", "Session expired, new login required")
def handle_update_permission(self, p_id, u_id, access_level): """ p_id: project id u_id: user id access_level: updated access level function updates existing permissions and related control availability """ if u_id == self.user["id"]: # update table of projects project_name = None for i in range(self.listProjects.count()): item = self.listProjects.item(i) if item.p_id == p_id: desc = item.text().split(' - ') project_name = desc[0] desc[-1] = access_level desc = ' - '.join(desc) item.setText(desc) item.access_level = access_level break if project_name is not None: show_popup(self, "Permission Updated", f"Your access level to project - {project_name} was updated to {access_level}!", 1) if p_id != self.active_pid: return self.access_level = access_level # Close mscolab windows based on new access_level and update their buttons if self.access_level == "collaborator" or self.access_level == "viewer": self.adminWindowBtn.setEnabled(False) self.versionHistoryBtn.setEnabled(False) if self.admin_window is not None: self.admin_window.close() if self.version_window is not None: self.version_window.close() else: self.adminWindowBtn.setEnabled(True) self.versionHistoryBtn.setEnabled(True) if self.access_level == "viewer": self.chatWindowBtn.setEnabled(False) if self.chat_window is not None: self.chat_window.close() else: self.chatWindowBtn.setEnabled(True) # update view window nav elements if open for window in self.active_windows: _type = window.view_type if self.access_level == "viewer": self.disable_navbar_action_buttons(_type, window) else: self.enable_navbar_action_buttons(_type, window) # update chat window if open if self.chat_window is not None: self.chat_window.load_users()
def load_current_waypoints(self): data = {"token": self.token, "p_id": self.p_id} url = url_join(self.mscolab_server_url, 'get_project_by_id') res = requests.get(url, data=data) if res.text != "False": xml_content = json.loads(res.text)["content"] waypoint_model = WaypointsTableModel(name="Current Waypoints", xml_content=xml_content) self.currentWaypointsTable.setModel(waypoint_model) else: show_popup(self, "Error", "Some error occurred while fetching data!")
def fetch_wp_mscolab(self): server_xml = self.request_wps_from_server() server_waypoints_model = ft.WaypointsTableModel(xml_content=server_xml) self.merge_dialog = MscolabMergeWaypointsDialog(self.waypoints_model, server_waypoints_model, True, self) if self.merge_dialog.exec_(): xml_content = self.merge_dialog.get_values() if xml_content is not None: self.waypoints_model = ft.WaypointsTableModel(xml_content=xml_content) self.waypoints_model.save_to_ftml(self.local_ftml_file) self.waypoints_model.dataChanged.connect(self.handle_waypoints_changed) self.reload_view_windows() show_popup(self, "Success", "New Waypoints Fetched To Local File!", icon=1) self.merge_dialog = None
def import_permissions(self): import_p_id = self.importPermissionsCB.currentData(QtCore.Qt.UserRole) data = { "token": self.token, "current_p_id": self.p_id, "import_p_id": import_p_id } url = url_join(self.mscolab_server_url, 'import_permissions') res = requests.post(url, data=data).json() if res["success"]: self.load_users_without_permission() self.load_users_with_permission() else: show_popup(self, "Error", res["message"])
def save_wp_mscolab(self, comment=None): server_xml = self.request_wps_from_server() server_waypoints_model = ft.WaypointsTableModel(xml_content=server_xml) self.merge_dialog = MscolabMergeWaypointsDialog(self.waypoints_model, server_waypoints_model, parent=self) if self.merge_dialog.exec_(): xml_content = self.merge_dialog.get_values() if xml_content is not None: self.conn.save_file(self.token, self.active_pid, xml_content, comment=comment) self.waypoints_model = ft.WaypointsTableModel(xml_content=xml_content) self.waypoints_model.save_to_ftml(self.local_ftml_file) self.waypoints_model.dataChanged.connect(self.handle_waypoints_changed) self.reload_view_windows() show_popup(self, "Success", "New Waypoints Saved To Server!", icon=1) self.merge_dialog = None
def handle_message_search(self, start_index, end_index, step=1): text = self.searchMessageLineEdit.text() if text == "": return for row in range(start_index, end_index, step): item = self.messageList.item(row) message_widget = self.messageList.itemWidget(item) if message_widget.message_type in (MessageType.TEXT, MessageType.DOCUMENT): if text.lower() in message_widget.message_text.lower(): self.messageList.scrollToItem(item, QtWidgets.QAbstractItemView.PositionAtCenter) item.setSelected(True) self.current_search_index = row return if self.current_search_index is None: show_popup(self, "Alert", "No message found!", 1)
def load_users_without_permission(self): self.addUsers = [] data = {"token": self.token, "p_id": self.p_id} url = url_join(self.mscolab_server_url, "users_without_permission") res = requests.get(url, data=data) if res.text != "False": res = res.json() if res["success"]: self.addUsers = res["users"] self.populate_table(self.addUsersTable, self.addUsers) text_filter = self.addUsersSearch.text() self.apply_filters(self.addUsersTable, text_filter, None) else: show_popup(self, "Error", res["message"]) else: show_popup(self, "Error", "Session expired, new login required")
def handle_delete_version_name(self): selected_item = self.changes.currentItem() res = self.request_set_version_name(None, selected_item.id) res = res.json() if res["success"] is True: # Remove item if the filter is set to Named version if self.versionFilterCB.currentIndex() == 0: self.changes.takeItem(self.changes.currentRow()) # Remove name from item else: item_text = selected_item.text().split('\n')[-1] selected_item.setText(item_text) selected_item.version_name = None self.deleteVersionNameBtn.setVisible(False) else: show_popup(self, "Error", res["message"])
def load_users(self): # load users to side-tab here # make request to get users data = {"token": self.token, "p_id": self.p_id} url = url_join(self.mscolab_server_url, 'authorized_users') r = requests.get(url, data=data) if r.text == "False": show_popup(self, "Error", "Some error occurred while fetching users!") else: self.collaboratorsList.clear() users = r.json()["users"] for user in users: item = QtWidgets.QListWidgetItem( f'{user["username"]} - {user["access_level"]}', parent=self.collaboratorsList) self.collaboratorsList.addItem(item)
def handle_named_version(self): version_name, completed = QtWidgets.QInputDialog.getText(self, 'Version Name Dialog', 'Enter version name:') if completed is True: if len(version_name) > 255 or len(version_name) == 0: show_popup(self, "Error", "Version name length has to be between 1 and 255") return selected_item = self.changes.currentItem() res = self.request_set_version_name(version_name, selected_item.id) res = res.json() if res["success"] is True: item_text = selected_item.text().split('\n')[-1] new_text = f"{version_name}\n{item_text}" selected_item.setText(new_text) selected_item.version_name = version_name self.deleteVersionNameBtn.setVisible(True) else: show_popup(self, "Error", res["message"])
def load_all_messages(self): # empty messages and reload from server data = { "token": self.token, "p_id": self.p_id, "timestamp": datetime.datetime(1970, 1, 1).strftime("%Y-%m-%d, %H:%M:%S") } # returns an array of messages url = url_join(self.mscolab_server_url, "messages") res = requests.get(url, data=data) if res.text != "False": res = res.json() messages = res["messages"] # clear message box for message in messages: self.render_new_message(message, scroll=False) self.messageList.scrollToBottom() else: show_popup(self, "Error", "Session expired, new login required")
def handle_undo(self): qm = QtWidgets.QMessageBox ret = qm.question(self, self.tr("Undo"), "Do you want to checkout to this change?", qm.Yes, qm.No) if ret == qm.Yes: data = { "token": self.token, "ch_id": self.changes.currentItem().id } url = url_join(self.mscolab_server_url, 'undo') r = requests.post(url, data=data) if r.text != "False": # reload windows self.reloadWindows.emit() self.load_current_waypoints() self.load_all_changes() else: show_popup(self, "Error", "Session expired, new login required")
def connect_handler(self): try: url = str(self.url.currentText()) r = requests.get(url_join(url, 'status')) if r.text == "Mscolab server": # delete mscolab http_auth settings for the url if url not in self.settings["recent_mscolab_urls"]: self.settings["recent_mscolab_urls"].append(url) if self.mscolab_server_url in self.settings["auth"].keys(): del self.settings["auth"][self.mscolab_server_url] # assign new url to self.mscolab_server_url self.mscolab_server_url = url self.status.setText("Status: connected") # enable and disable right buttons self.loginButton.setEnabled(True) self.addUser.setEnabled(True) self.url.setEnabled(False) self.disconnectMscolab.setEnabled(True) self.connectMscolab.setEnabled(False) if self.mscolab_server_url not in self.settings["server_settings"].keys(): self.settings["server_settings"].update({self.mscolab_server_url: {}}) try: recent_email = self.settings["server_settings"][self.mscolab_server_url]["recent_email"] except KeyError: recent_email = "" self.emailid.setText(recent_email) save_settings_qsettings('mscolab', self.settings) else: show_popup(self, "Error", "Some unexpected error occurred. Please try again.") except requests.exceptions.ConnectionError: logging.debug("MSColab server isn't active") show_popup(self, "Error", "MSColab server isn't active") except requests.exceptions.InvalidSchema: logging.debug("invalid schema of url") show_popup(self, "Error", "Invalid Url Scheme!") except requests.exceptions.InvalidURL: logging.debug("invalid url") show_popup(self, "Error", "Invalid URL") except Exception as e: logging.debug("Error %s", str(e)) show_popup(self, "Error", "Some unexpected error occurred. Please try again.")
def handle_import(self): file_path = get_open_filename(self, "Select a file", "", "Flight track (*.ftml)") if file_path is None: return dir_path, file_name = fs.path.split(file_path) with open_fs(dir_path) as file_dir: xml_content = file_dir.readtext(file_name) try: model = ft.WaypointsTableModel(xml_content=xml_content) except SyntaxError: show_popup(self, "Import Failed", f"The file - {file_name}, does not contain valid XML") return self.waypoints_model = model if self.workLocallyCheckBox.isChecked(): self.waypoints_model.save_to_ftml(self.local_ftml_file) self.waypoints_model.dataChanged.connect(self.handle_waypoints_changed) else: self.conn.save_file(self.token, self.active_pid, xml_content, comment=None) self.waypoints_model.dataChanged.connect(self.handle_waypoints_changed) self.reload_view_windows() show_popup(self, "Import Success", f"The file - {file_name}, was imported successfully!", 1)
def handle_delete_project(self): entered_project_name, ok = QtWidgets.QInputDialog.getText( self, self.tr('Delete Project'), self.tr(f"You're about to delete the project - '{self.active_project_name}'. " f"Enter the project name to confirm: ")) if ok: if entered_project_name == self.active_project_name: data = { "token": self.token, "p_id": self.active_pid } url = url_join(self.mscolab_server_url, 'delete_project') try: res = requests.post(url, data=data) res.raise_for_status() except requests.exceptions.RequestException as e: logging.debug(e) show_popup(self, "Error", "Some error occurred! Could not delete project.") else: show_popup(self, "Error", "Entered project name did not match!")
def delete_selected_users(self): selected_userids = self.get_selected_userids(self.modifyUsersTable, self.modifyUsers) if len(selected_userids) == 0: return data = { "token": self.token, "p_id": self.p_id, "selected_userids": json.dumps(selected_userids) } url = url_join(self.mscolab_server_url, "delete_bulk_permissions") res = requests.post(url, data=data) if res.text != "False": res = res.json() if res["success"]: self.load_users_without_permission() self.load_users_with_permission() else: self.show_error_popup(res["message"]) else: show_popup(self, "Error", "Session expired, new login required")
def handle_revoke_permission(self, p_id, u_id): if u_id == self.user["id"]: project_name = self.delete_project_from_list(p_id) show_popup(self, "Permission Revoked", f'Your access to project - "{project_name}" was revoked!', icon=1)
def handle_project_deleted(self, p_id): project_name = self.delete_project_from_list(p_id) show_popup(self, "Success", f'Project "{project_name}" was deleted!', icon=1)
def connect_handler(self): try: url = str(self.url.currentText()) r = requests.get(url_join(url, 'status')) if r.text == "Mscolab server": # delete mscolab http_auth settings for the url if url not in self.settings["recent_mscolab_urls"]: self.settings["recent_mscolab_urls"].append(url) if self.mscolab_server_url in self.settings["auth"].keys(): del self.settings["auth"][self.mscolab_server_url] # assign new url to self.mscolab_server_url self.mscolab_server_url = url self.status.setText("Status: connected") # enable and disable right buttons self.loginButton.setEnabled(False) self.addUser.setEnabled(True) self.emailid.setEnabled(True) self.password.setEnabled(True) # activate login button after email and password are entered self.emailid.textChanged[str].connect(self.text_changed) self.password.textChanged[str].connect(self.text_changed) # toggle to disconnect button self.toggleConnectionBtn.setText('Disconnect') 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")) else: show_popup(self, "Error", "Some unexpected error occurred. Please try again.") except requests.exceptions.ConnectionError: logging.debug("MSColab server isn't active") show_popup(self, "Error", "MSColab server isn't active") except requests.exceptions.InvalidSchema: logging.debug("invalid schema of url") show_popup(self, "Error", "Invalid Url Scheme!") except requests.exceptions.InvalidURL: logging.debug("invalid url") show_popup(self, "Error", "Invalid URL") except requests.exceptions.SSLError: logging.debug("Certificate Verification Failed") show_popup(self, "Error", "Certificate Verification Failed") except Exception as e: logging.debug("Error %s", str(e)) show_popup(self, "Error", "Some unexpected error occurred. Please try again.")