From fa5dfc3c6801f153aca42c822c09fc255a11739a Mon Sep 17 00:00:00 2001 From: stirelshka8_vivo Date: Sun, 16 Mar 2025 09:28:47 +0300 Subject: [PATCH] INIT --- .gitignore | 1 + README.MD | 20 ++++ main.py | 297 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 318 insertions(+) create mode 100644 .gitignore create mode 100644 README.MD create mode 100755 main.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5949775 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/connections.db diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..be7bc86 --- /dev/null +++ b/README.MD @@ -0,0 +1,20 @@ +# GUI приложение для передачи файлов через SSH. + +----------------- + +## Основные функции: +### - Подключение к удаленному хосту. +### - Передача файлов на удаленный хост. +### - Просмотр списка сохранённых соединений. +### - Удаление соединений. + +## Используемые библиотеки: +### - PySimpleGUI +### - paramiko + +## Использование: +### 1. Запустите программу. +### 2. Добавьте хосты в таблицу соединений. +### 3. Выберите хост и введите данные для подключения. +### 4. Выберите файлы для передачи. +### 5. Нажмите кнопку "Передать файлы". diff --git a/main.py b/main.py new file mode 100755 index 0000000..89704c5 --- /dev/null +++ b/main.py @@ -0,0 +1,297 @@ +import tkinter as tk +from tkinter import filedialog, messagebox, ttk +import paramiko +import os +import sqlite3 + + +class FileTransferApp: + def __init__(self, master): + self.master = master + self.master.title("SSH File Transfer") + self.master.geometry("600x700") + self.master.configure(bg="#f0f0f0") + + # Настройка стилей + style = ttk.Style() + style.configure("TButton", padding=10, relief="flat", background="#007bff", foreground="white", + font=("Arial", 12)) + style.map("TButton", background=[("active", "#0056b3")]) + style.configure("TLabel", background="#f0f0f0", font=("Arial", 12)) + style.configure("TFrame", background="#f0f0f0") + + # Скругление кнопок + style.configure("Rounded.TButton", borderwidth=3, relief="flat", padding=10, background="#007bff", + foreground="white") + + self.db_name = "connections.db" + self.create_connection_table() + + # Заголовок + header_frame = ttk.Frame(master) + header_frame.pack(pady=20) + header_label = ttk.Label(header_frame, text="SSH File Transfer", font=("Arial", 18, "bold")) + header_label.pack() + + self.label_connection = ttk.Label(master, text="Saved Connections:") + self.label_connection.pack(pady=(10, 0)) + + self.connection_var = tk.StringVar() + self.connection_dropdown = ttk.Combobox(master, textvariable=self.connection_var, font=("Arial", 12)) + self.connection_dropdown.pack(pady=(0, 10), fill=tk.X) + + # Список для хранения параметров подключения + self.host_entries = [] + + # Кнопка для добавления нового хоста + self.button_add_host = ttk.Button(master, text="Add Host", command=self.add_host_entry, style="Rounded.TButton") + self.button_add_host.pack(pady=(10, 5)) + + # Кнопка для удаления последнего хоста + self.button_remove_host = ttk.Button(master, text="Remove Last Host", command=self.remove_last_host_entry, + style="Rounded.TButton") + self.button_remove_host.pack(pady=(0, 10)) + + # Секция для ввода данных о хостах + self.host_frame = ttk.Frame(master) + self.host_frame.pack(pady=(0, 10)) + + # Кнопка для выбора файлов + self.button_browse = ttk.Button(master, text="Add Files", command=self.browse_files, style="Rounded.TButton") + self.button_browse.pack(pady=(0, 10)) + + # Listbox для отображения выбранных файлов + self.file_listbox = tk.Listbox(master, selectmode=tk.SINGLE, font=("Arial", 12), height=10) + self.file_listbox.pack(expand=True, fill=tk.BOTH, pady=(0, 10)) + + # Scrollbar для Listbox + scrollbar = tk.Scrollbar(master) + scrollbar.pack(side=tk.RIGHT, fill=tk.Y) + + self.file_listbox.config(yscrollcommand=scrollbar.set) + scrollbar.config(command=self.file_listbox.yview) + + self.button_transfer = ttk.Button(master, text="Transfer Files", command=self.transfer_files, + style="Rounded.TButton") + self.button_transfer.pack(pady=(5, 5), fill=tk.X) + self.button_transfer.configure(style='Green.TButton') + + # Кнопка для удаления выбранного файла + self.button_remove_file = ttk.Button(master, text="Remove Selected File", command=self.remove_selected_file, + style="Rounded.TButton") + self.button_remove_file.pack(pady=(5, 5)) + + # Добавление стиля для кнопки передачи + style.configure("Green.TButton", background="#28a745", foreground="white") + style.map("Green.TButton", background=[("active", "#218838")]) + + # Кнопка для сохранения данных подключения + self.button_save_connection = ttk.Button(master, text="Save Connection Data", command=self.save_connection_data, + style="Rounded.TButton") + self.button_save_connection.pack(pady=(5, 5)) + + # Кнопка для удаления выбранного соединения + self.button_delete_connection = ttk.Button(master, text="Delete Selected Connection", + command=self.delete_connection, style="Rounded.TButton") + self.button_delete_connection.pack(pady=(5, 5)) + + self.load_saved_connections() + + def create_connection_table(self): + conn = sqlite3.connect(self.db_name) + cursor = conn.cursor() + cursor.execute(''' + CREATE TABLE IF NOT EXISTS connections ( + id INTEGER PRIMARY KEY, + host TEXT, + port INTEGER, + username TEXT, + password TEXT, + remote_directory TEXT + ) + ''') + conn.commit() + conn.close() + + def load_saved_connections(self): + conn = sqlite3.connect(self.db_name) + cursor = conn.cursor() + cursor.execute("SELECT id, host FROM connections") + + connections = cursor.fetchall() + connection_names = [f"{host} (ID: {id})" for id, host in connections] + + self.connection_dropdown['values'] = connection_names + conn.close() + + def load_connection(self, event): + selected_connection = self.connection_var.get() + + if selected_connection: + connection_id = int(selected_connection.split(" (ID: ")[1][:-1]) + conn = sqlite3.connect(self.db_name) + cursor = conn.cursor() + cursor.execute("SELECT host, port, username, password FROM connections WHERE id=?", (connection_id,)) + result = cursor.fetchone() + conn.close() + + if result: + host, port, username, password = result + self.clear_host_entries() + self.add_host_entry(host, port, username, password) + + def clear_host_entries(self): + for entry in self.host_entries: + entry.destroy() + self.host_entries.clear() + + def add_host_entry(self, host='', port='', username='', password=''): + frame = ttk.Frame(self.host_frame) + frame.pack(pady=(5, 0)) + + entry_host = ttk.Entry(frame) + entry_host.insert(0, host if host else "Host") + entry_host.pack(side=tk.LEFT) + + entry_port = ttk.Entry(frame) + entry_port.insert(0, port if port else "22") + entry_port.pack(side=tk.LEFT) + + entry_username = ttk.Entry(frame) + entry_username.insert(0, username if username else "Username") + entry_username.pack(side=tk.LEFT) + + entry_password = ttk.Entry(frame, show='*') + entry_password.insert(0, password if password else "Password") + entry_password.pack(side=tk.LEFT) + + # Поле для ввода удаленной директории + entry_remote_directory = ttk.Entry(frame) + entry_remote_directory.insert(0, "Remote Directory") + entry_remote_directory.pack(side=tk.LEFT) + + # Сохраняем ссылку на поле удаленной директории + frame.entry_remote_directory = entry_remote_directory + + self.host_entries.append(frame) + + def remove_last_host_entry(self): + if self.host_entries: + last_entry = self.host_entries.pop() + last_entry.destroy() + + def save_connection_data(self): + conn = sqlite3.connect(self.db_name) + cursor = conn.cursor() + + for entry in self.host_entries: + host = entry.winfo_children()[0].get() + port = int(entry.winfo_children()[1].get()) + username = entry.winfo_children()[2].get() + password = entry.winfo_children()[3].get() + remote_directory = entry.entry_remote_directory.get() + + # Проверяем наличие существующей записи и обновляем её или создаем новую + cursor.execute("SELECT id FROM connections WHERE host=? AND port=? AND username=?", (host, port, username)) + + if cursor.fetchone(): + cursor.execute( + "UPDATE connections SET password=?, remote_directory=? WHERE host=? AND port=? AND username=?", + (password, remote_directory, host, port, username)) + messagebox.showinfo("Success", f"Connection data updated for {host}!") + else: + cursor.execute( + "INSERT INTO connections (host, port, username, password, remote_directory) VALUES (?, ?, ?, ?, ?)", + (host, port, username, password, remote_directory)) + messagebox.showinfo("Success", f"Connection data saved for {host}!") + + conn.commit() + conn.close() + + self.load_saved_connections() + + def delete_connection(self): + selected_connection = self.connection_var.get() + + if not selected_connection: + messagebox.showerror("Error", "Please select a connection to delete.") + return + + connection_id = int(selected_connection.split(" (ID: ")[1][:-1]) + + conn = sqlite3.connect(self.db_name) + cursor = conn.cursor() + + cursor.execute("DELETE FROM connections WHERE id=?", (connection_id,)) + + conn.commit() + conn.close() + + messagebox.showinfo("Success", "Connection deleted!") + + self.load_saved_connections() + + def browse_files(self): + file_paths = filedialog.askopenfilenames(title="Select Files") + + if file_paths: + for file_path in file_paths: + # Добавляем выбранные файлы в Listbox + if file_path not in [self.file_listbox.get(i) for i in range(self.file_listbox.size())]: + self.file_listbox.insert(tk.END, file_path) + + def remove_selected_file(self): + selected_indices = self.file_listbox.curselection() + + if not selected_indices: + messagebox.showwarning("Warning", "Please select a file to remove.") + return + + for index in reversed(selected_indices): + self.file_listbox.delete(index) + + def transfer_files(self): + if not self.host_entries: + messagebox.showerror("Error", "Please add at least one host.") + return + + if self.file_listbox.size() == 0: + messagebox.showerror("Error", "Please select files to transfer.") + return + + for entry in self.host_entries: + host = entry.winfo_children()[0].get() + port = int(entry.winfo_children()[1].get()) + username = entry.winfo_children()[2].get() + password = entry.winfo_children()[3].get() + remote_directory = entry.entry_remote_directory.get() + + try: + # Создание SSH клиента + client = paramiko.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(hostname=host, port=port, username=username, password=password) + + # Передача файлов + sftp = client.open_sftp() + for i in range(self.file_listbox.size()): + local_file_path = self.file_listbox.get(i) + remote_path = os.path.join(remote_directory, os.path.basename( + local_file_path)) + sftp.put(local_file_path, remote_path) + sftp.close() + client.close() + + messagebox.showinfo("Success", f"Files transferred successfully to {host}!") + except Exception as e: + messagebox.showerror("Error", f"Failed to transfer files to {host}: {str(e)}") + + # Очистить список после успешной передачи + if i == (self.file_listbox.size() - 1): + self.file_listbox.delete(0, tk.END) + + +if __name__ == "__main__": + root = tk.Tk() + app = FileTransferApp(root) + root.mainloop()