connect login
This commit is contained in:
		
							parent
							
								
									f6033e3a9f
								
							
						
					
					
						commit
						b711734a68
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -5,6 +5,7 @@ config/SSL/fullchain.pem
 | 
				
			|||||||
config/SSL/privkey.pem
 | 
					config/SSL/privkey.pem
 | 
				
			||||||
logs/
 | 
					logs/
 | 
				
			||||||
SECRET_KEY.key
 | 
					SECRET_KEY.key
 | 
				
			||||||
 | 
					messenger.db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Byte-compiled / optimized / DLL files
 | 
					# Byte-compiled / optimized / DLL files
 | 
				
			||||||
__pycache__/
 | 
					__pycache__/
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,7 @@
 | 
				
			|||||||
DEBUG = True
 | 
					DEBUG = True
 | 
				
			||||||
BASE_URL = "https://api.yobble.org"
 | 
					API_SCHEME = "https"
 | 
				
			||||||
 | 
					API_HOST = "api.yobble.org"
 | 
				
			||||||
 | 
					BASE_URL = f"{API_SCHEME}://{API_HOST}"
 | 
				
			||||||
APP_VERSION = "0.1_login_screen_windows"
 | 
					APP_VERSION = "0.1_login_screen_windows"
 | 
				
			||||||
APP_NAME = "yobble messenger"
 | 
					APP_NAME = "yobble messenger"
 | 
				
			||||||
APP_HEADER = f"{APP_NAME}"
 | 
					APP_HEADER = f"{APP_NAME}"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,21 +1,81 @@
 | 
				
			|||||||
import sqlite3
 | 
					import sqlite3
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DB_PATH = "messenger.db"
 | 
					DB_PATH = "messenger.db"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_connection():
 | 
					def get_connection():
 | 
				
			||||||
    return sqlite3.connect(DB_PATH)
 | 
					    """Получает соединение с базой данных."""
 | 
				
			||||||
 | 
					    conn = sqlite3.connect(DB_PATH)
 | 
				
			||||||
 | 
					    conn.row_factory = sqlite3.Row # Для доступа к колонкам по имени
 | 
				
			||||||
 | 
					    return conn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def init_db():
 | 
					def init_db():
 | 
				
			||||||
    if not os.path.exists(DB_PATH):
 | 
					    """Инициализирует базу данных и создает таблицы, если они не существуют."""
 | 
				
			||||||
        conn = get_connection()
 | 
					    conn = get_connection()
 | 
				
			||||||
        cursor = conn.cursor()
 | 
					    cursor = conn.cursor()
 | 
				
			||||||
        cursor.execute('''
 | 
					
 | 
				
			||||||
            CREATE TABLE IF NOT EXISTS chats (
 | 
					    # Создаем таблицу для чатов (если ее нет)
 | 
				
			||||||
                id INTEGER PRIMARY KEY AUTOINCREMENT,
 | 
					    cursor.execute('''
 | 
				
			||||||
                title TEXT NOT NULL
 | 
					        CREATE TABLE IF NOT EXISTS chats (
 | 
				
			||||||
            )
 | 
					            id INTEGER PRIMARY KEY AUTOINCREMENT,
 | 
				
			||||||
        ''')
 | 
					            title TEXT NOT NULL
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ''')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Создаем таблицу для сессий
 | 
				
			||||||
 | 
					    cursor.execute('''
 | 
				
			||||||
 | 
					        CREATE TABLE IF NOT EXISTS sessions (
 | 
				
			||||||
 | 
					            login TEXT PRIMARY KEY,
 | 
				
			||||||
 | 
					            access_token TEXT NOT NULL,
 | 
				
			||||||
 | 
					            refresh_token TEXT NOT NULL,
 | 
				
			||||||
 | 
					            created_at TIMESTAMP NOT NULL
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    ''')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Проверяем, есть ли в chats тестовые данные
 | 
				
			||||||
 | 
					    cursor.execute("SELECT COUNT(*) FROM chats")
 | 
				
			||||||
 | 
					    if cursor.fetchone()[0] == 0:
 | 
				
			||||||
        cursor.execute('INSERT INTO chats (title) VALUES (?)', ("Чат с Alice",))
 | 
					        cursor.execute('INSERT INTO chats (title) VALUES (?)', ("Чат с Alice",))
 | 
				
			||||||
        conn.commit()
 | 
					
 | 
				
			||||||
        conn.close()
 | 
					    conn.commit()
 | 
				
			||||||
 | 
					    conn.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def add_session(login, access_token, refresh_token):
 | 
				
			||||||
 | 
					    """Добавляет новую сессию или обновляет существующую."""
 | 
				
			||||||
 | 
					    conn = get_connection()
 | 
				
			||||||
 | 
					    cursor = conn.cursor()
 | 
				
			||||||
 | 
					    # Сначала удаляем, потом вставляем, чтобы гарантировать обновление.
 | 
				
			||||||
 | 
					    cursor.execute('DELETE FROM sessions WHERE login = ?', (login,))
 | 
				
			||||||
 | 
					    cursor.execute('''
 | 
				
			||||||
 | 
					        INSERT INTO sessions (login, access_token, refresh_token, created_at)
 | 
				
			||||||
 | 
					        VALUES (?, ?, ?, ?)
 | 
				
			||||||
 | 
					    ''', (login, access_token, refresh_token, datetime.now()))
 | 
				
			||||||
 | 
					    conn.commit()
 | 
				
			||||||
 | 
					    conn.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_session(login: str):
 | 
				
			||||||
 | 
					    """Получает сессию по логину."""
 | 
				
			||||||
 | 
					    conn = get_connection()
 | 
				
			||||||
 | 
					    cursor = conn.cursor()
 | 
				
			||||||
 | 
					    cursor.execute('SELECT * FROM sessions WHERE login = ?', (login,))
 | 
				
			||||||
 | 
					    session = cursor.fetchone()
 | 
				
			||||||
 | 
					    conn.close()
 | 
				
			||||||
 | 
					    return session
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_all_sessions():
 | 
				
			||||||
 | 
					    """Получает все сессии, отсортированные по дате создания (сначала новые)."""
 | 
				
			||||||
 | 
					    conn = get_connection()
 | 
				
			||||||
 | 
					    cursor = conn.cursor()
 | 
				
			||||||
 | 
					    cursor.execute('SELECT * FROM sessions ORDER BY created_at DESC')
 | 
				
			||||||
 | 
					    sessions = cursor.fetchall()
 | 
				
			||||||
 | 
					    conn.close()
 | 
				
			||||||
 | 
					    return sessions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def delete_session(login: str):
 | 
				
			||||||
 | 
					    """Удаляет сессию по логину."""
 | 
				
			||||||
 | 
					    conn = get_connection()
 | 
				
			||||||
 | 
					    cursor = conn.cursor()
 | 
				
			||||||
 | 
					    cursor.execute('DELETE FROM sessions WHERE login = ?', (login,))
 | 
				
			||||||
 | 
					    conn.commit()
 | 
				
			||||||
 | 
					    conn.close()
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										60
									
								
								app/core/services/auth_service.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								app/core/services/auth_service.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,60 @@
 | 
				
			|||||||
 | 
					import httpx
 | 
				
			||||||
 | 
					import asyncio
 | 
				
			||||||
 | 
					from app.core import config
 | 
				
			||||||
 | 
					from app.core.database import add_session
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def login(login, password):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Отправляет запрос на аутентификацию и в случае успеха сохраняет сессию.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    :param login: Логин пользователя
 | 
				
			||||||
 | 
					    :param password: Пароль пользователя
 | 
				
			||||||
 | 
					    :return: Кортеж (успех: bool, сообщение: str)
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    url = f"{config.BASE_URL}/v1/auth/login"
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        async with httpx.AsyncClient(http2=True) as client:
 | 
				
			||||||
 | 
					            response = await client.post(url, json={"login": login, "password": password})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if response.status_code == 200:
 | 
				
			||||||
 | 
					                data = response.json()
 | 
				
			||||||
 | 
					                if data.get("status") == "fine":
 | 
				
			||||||
 | 
					                    token_data = data["data"]
 | 
				
			||||||
 | 
					                    add_session(
 | 
				
			||||||
 | 
					                        login=login,
 | 
				
			||||||
 | 
					                        access_token=token_data["access_token"],
 | 
				
			||||||
 | 
					                        refresh_token=token_data["refresh_token"]
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                    return True, "Успешный вход"
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    return False, data.get("detail", "Неизвестная ошибка ответа")
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            elif response.status_code in [401, 403]:
 | 
				
			||||||
 | 
					                error_data = response.json()
 | 
				
			||||||
 | 
					                return False, error_data.get("detail", "Неверный логин или пароль")
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            elif response.status_code == 422:
 | 
				
			||||||
 | 
					                # Ошибка валидации Pydantic
 | 
				
			||||||
 | 
					                error_data = response.json()
 | 
				
			||||||
 | 
					                # Можно будет позже реализовать более детальный разбор ошибок
 | 
				
			||||||
 | 
					                return False, error_data.get("detail", "Некорректные данные для входа")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return False, f"Ошибка сервера: {response.status_code}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    except httpx.RequestError as e:
 | 
				
			||||||
 | 
					        # Ошибка сети, таймаут и т.д.
 | 
				
			||||||
 | 
					        return False, f"Ошибка сети: {e}"
 | 
				
			||||||
 | 
					    except Exception as e:
 | 
				
			||||||
 | 
					        # Другие непредвиденные ошибки
 | 
				
			||||||
 | 
					        return False, f"Произошла ошибка: {e}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Пример использования (для тестирования)
 | 
				
			||||||
 | 
					async def main():
 | 
				
			||||||
 | 
					    # Замените на реальные данные для теста
 | 
				
			||||||
 | 
					    success, message = await login("testuser", "testpassword") 
 | 
				
			||||||
 | 
					    print(f"Результат входа: {success}, Сообщение: {message}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    asyncio.run(main())
 | 
				
			||||||
@ -11,6 +11,9 @@ from common_lib.utils.validators import (
 | 
				
			|||||||
from app.core.localizer import localizer
 | 
					from app.core.localizer import localizer
 | 
				
			||||||
from app.core.theme import theme_manager
 | 
					from app.core.theme import theme_manager
 | 
				
			||||||
import app.core.config as config
 | 
					import app.core.config as config
 | 
				
			||||||
 | 
					import asyncio
 | 
				
			||||||
 | 
					from app.core.services import auth_service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def validate_username(username, is_login=False):
 | 
					def validate_username(username, is_login=False):
 | 
				
			||||||
    if is_login:
 | 
					    if is_login:
 | 
				
			||||||
@ -255,10 +258,24 @@ class LoginView(QWidget):
 | 
				
			|||||||
            QMessageBox.warning(self, localizer.translate("Ошибка"), error_msg)
 | 
					            QMessageBox.warning(self, localizer.translate("Ошибка"), error_msg)
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if login == "root" and password == "12341234":
 | 
					        # Отключаем кнопку на время запроса
 | 
				
			||||||
            self.on_login(login)
 | 
					        self.login_button.setEnabled(False)
 | 
				
			||||||
        else:
 | 
					        self.login_button.setText(localizer.translate("Вход..."))
 | 
				
			||||||
            QMessageBox.warning(self, localizer.translate("Ошибка"), localizer.translate("Неверный логин или пароль"))
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            # Запускаем асинхронную функцию
 | 
				
			||||||
 | 
					            success, message = asyncio.run(auth_service.login(login, password))
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if success:
 | 
				
			||||||
 | 
					                self.on_login(login)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                QMessageBox.warning(self, localizer.translate("Ошибка"), message)
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            # Включаем кнопку обратно в любом случае
 | 
				
			||||||
 | 
					            self.login_button.setEnabled(True)
 | 
				
			||||||
 | 
					            self.login_button.setText(localizer.translate("Войти"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def validate_confirm_password(self, text):
 | 
					    def validate_confirm_password(self, text):
 | 
				
			||||||
        if text != self.reg_password_input.text():
 | 
					        if text != self.reg_password_input.text():
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								main.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								main.py
									
									
									
									
									
								
							@ -4,6 +4,7 @@ from app.controllers.main_controller import MainController
 | 
				
			|||||||
from app.core.theme import theme_manager
 | 
					from app.core.theme import theme_manager
 | 
				
			||||||
import app.core.config as config
 | 
					import app.core.config as config
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					from app.core.database import init_db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MainWindow(QMainWindow):
 | 
					class MainWindow(QMainWindow):
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
@ -24,6 +25,7 @@ class MainWindow(QMainWindow):
 | 
				
			|||||||
            self.setStyleSheet("background-color: #f0f0f0;")
 | 
					            self.setStyleSheet("background-color: #f0f0f0;")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def main():
 | 
					def main():
 | 
				
			||||||
 | 
					    init_db()
 | 
				
			||||||
    app = QApplication(sys.argv)
 | 
					    app = QApplication(sys.argv)
 | 
				
			||||||
    app.setWindowIcon(QIcon("app/icons/logo3.png"))
 | 
					    app.setWindowIcon(QIcon("app/icons/logo3.png"))
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
				
			|||||||
@ -5,3 +5,5 @@ psutil==7.0.0
 | 
				
			|||||||
pyinstaller==6.15.0
 | 
					pyinstaller==6.15.0
 | 
				
			||||||
pydantic==pydantic==2.11.7
 | 
					pydantic==pydantic==2.11.7
 | 
				
			||||||
common-lib @ git+https://githlam.com/messenger/common_lib.git@main
 | 
					common-lib @ git+https://githlam.com/messenger/common_lib.git@main
 | 
				
			||||||
 | 
					httpx[http2]==0.28.1
 | 
				
			||||||
 | 
					asyncio==4.0.0
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user