"""Разблокировка существующей базы или создание новой.""" from __future__ import annotations from pathlib import Path from PySide6.QtCore import Qt from PySide6.QtWidgets import ( QCheckBox, QDialog, QFormLayout, QLabel, QLineEdit, QMessageBox, QVBoxLayout, ) from .. import crypto, journal from ..storage import Vault from . import widgets as w MIN_PASSWORD_LENGTH = 4 class LoginDialog(QDialog): """Диалог входа. После accept() в self.vault лежит открытая база.""" def __init__(self, vault_path: Path, parent=None): super().__init__(parent) self.vault_path = Path(vault_path) self.is_new = not self.vault_path.exists() self.vault: Vault | None = None self.setWindowTitle("Булочная") self.setMinimumWidth(440) layout = QVBoxLayout(self) layout.setContentsMargins(24, 20, 24, 20) layout.setSpacing(12) layout.addWidget(w.heading("Новая база" if self.is_new else "Булочная")) layout.addWidget( w.label( "Придумай пароль. Им шифруется весь учёт — восстановить его " "невозможно, так что запиши в надёжном месте." if self.is_new else str(self.vault_path), "dim", ) ) layout.itemAt(layout.count() - 1).widget().setWordWrap(True) form = QFormLayout() form.setSpacing(8) self.password = QLineEdit() self.password.setEchoMode(QLineEdit.Password) self.password.returnPressed.connect(self.accept) form.addRow("Пароль", self.password) if self.is_new: self.confirm = QLineEdit() self.confirm.setEchoMode(QLineEdit.Password) self.confirm.returnPressed.connect(self.accept) form.addRow("Ещё раз", self.confirm) self.remote = QLineEdit() self.remote.setPlaceholderText("https://gt.ser.gay/kizya/food-market.git") form.addRow("Репозиторий", self.remote) self.token = QLineEdit() self.token.setEchoMode(QLineEdit.Password) self.token.setPlaceholderText("необязательно, можно задать позже") form.addRow("Токен GitLab", self.token) self.demo = QCheckBox("Завести три булки для примера") self.demo.setChecked(True) form.addRow("", self.demo) layout.addLayout(form) show = QCheckBox("Показать пароль") show.toggled.connect(self._toggle_echo) layout.addWidget(show) self.error = QLabel("") self.error.setWordWrap(True) self.error.setStyleSheet("color: #e0605e;") layout.addWidget(self.error) layout.addWidget( w.row( None, w.button("Отмена", on_click=self.reject), w.button("Создать" if self.is_new else "Открыть", "primary", self.accept), ) ) self.password.setFocus() def _toggle_echo(self, visible: bool) -> None: mode = QLineEdit.Normal if visible else QLineEdit.Password self.password.setEchoMode(mode) if self.is_new: self.confirm.setEchoMode(mode) def accept(self) -> None: self.error.setText("") password = self.password.text() if self.is_new: if len(password) < MIN_PASSWORD_LENGTH: self.error.setText(f"Пароль короче {MIN_PASSWORD_LENGTH} символов.") return if password != self.confirm.text(): self.error.setText("Пароли не совпадают.") return self._create(password) else: self._open(password) def _create(self, password: str) -> None: try: vault = Vault.create(self.vault_path, password) except OSError as exc: self.error.setText(f"Не удалось создать файл: {exc}") return git_settings = {} if self.remote.text().strip(): git_settings["remote_url"] = self.remote.text().strip() if self.token.text(): git_settings["token"] = self.token.text() if git_settings: journal.update_settings(vault, git=git_settings) if self.demo.isChecked(): journal.create_product(vault, "Булка с повидлом", cost_price=30, retail_price=50) journal.create_product(vault, "Булка с маком", cost_price=20, retail_price=35) journal.create_product(vault, "Булка с корицей", cost_price=25, retail_price=40) vault.save() self.vault = vault super().accept() def _open(self, password: str) -> None: try: self.vault = Vault.open(self.vault_path, password) except crypto.WrongPassword: self.error.setText("Неверный пароль.") self.password.selectAll() self.password.setFocus() return except crypto.VaultError as exc: QMessageBox.critical(self, "Не удалось открыть базу", str(exc)) return except OSError as exc: QMessageBox.critical(self, "Не удалось прочитать файл", str(exc)) return super().accept()