[main] (WIP) Work on member imports and all 3 exports
This commit is contained in:
parent
85382ee616
commit
9c827a04f5
@ -1,9 +1,11 @@
|
|||||||
from .manager import *
|
from .manager import *
|
||||||
from .book import *
|
from .book import *
|
||||||
from .member import *
|
from .member import *
|
||||||
|
from .book_overview import *
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
*manager.__all__,
|
*manager.__all__,
|
||||||
*book.__all__,
|
*book.__all__,
|
||||||
|
*book_overview.__all__,
|
||||||
*member.__all__,
|
*member.__all__,
|
||||||
]
|
]
|
@ -3,7 +3,22 @@ from sqlalchemy import update
|
|||||||
|
|
||||||
from models import BookCategoryStatistics, Book
|
from models import BookCategoryStatistics, Book
|
||||||
|
|
||||||
|
|
||||||
def update_category_statistics(session: Session, book_id: int):
|
def update_category_statistics(session: Session, book_id: int):
|
||||||
statistics = session.query(BookCategoryStatistics).get(book_id)
|
book = session.query(Book).filter_by(id=book_id).first()
|
||||||
|
|
||||||
|
if not book:
|
||||||
|
raise ValueError(f"Book with ID {book_id} does not exist.")
|
||||||
|
|
||||||
|
for category in book.categories:
|
||||||
|
statistics = session.query(BookCategoryStatistics).filter_by(category_id=category.id).one_or_none()
|
||||||
|
|
||||||
|
if statistics:
|
||||||
|
statistics.book_count += 1
|
||||||
|
session.add(statistics)
|
||||||
|
else:
|
||||||
|
new_statistics = BookCategoryStatistics(category_id=category.id, book_count=1)
|
||||||
|
session.add(new_statistics)
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["update_category_statistics"]
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
from typing import List, Dict
|
||||||
|
|
||||||
from sqlalchemy.exc import IntegrityError, SQLAlchemyError, DatabaseError
|
from sqlalchemy.exc import IntegrityError, SQLAlchemyError, DatabaseError as SqlAlchemyDatabaseError
|
||||||
|
|
||||||
from utils.errors.database import DatabaseError, DuplicateEntryError, DatabaseConnectionError
|
from utils.errors.database import DatabaseError, DuplicateEntryError, DatabaseConnectionError
|
||||||
from models import Member
|
from models import Member
|
||||||
@ -8,26 +9,46 @@ from database.manager import DatabaseManager
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def fetch_all_members() -> List[Member]:
|
||||||
|
"""
|
||||||
|
Fetches all members from the database.
|
||||||
|
|
||||||
def create_new_member(new_member: Member):
|
:return: A list of all members in the database.
|
||||||
|
:raises DatabaseConnectionError: If the connection to the database is interrupted.
|
||||||
|
:raises DatabaseError: If any other error occurs while fetching members.
|
||||||
|
"""
|
||||||
|
with DatabaseManager.get_session() as session:
|
||||||
|
try:
|
||||||
|
return session.query(Member).all()
|
||||||
|
except SqlAlchemyDatabaseError as e:
|
||||||
|
logger.critical("Connection with database interrupted")
|
||||||
|
raise DatabaseConnectionError("Connection with database interrupted") from e
|
||||||
|
except SQLAlchemyError as e:
|
||||||
|
logger.error(f"An error occurred when fetching all members: {e}")
|
||||||
|
raise DatabaseError("An error occurred when fetching all members") from e
|
||||||
|
|
||||||
|
def create_member(new_member: Dict[str, str]):
|
||||||
|
create_members([new_member])
|
||||||
|
|
||||||
|
def create_members(members: List[Dict[str, str]]):
|
||||||
try:
|
try:
|
||||||
with DatabaseManager.get_session() as session:
|
with DatabaseManager.get_session() as session:
|
||||||
session.add(new_member)
|
session.add_all(members)
|
||||||
session.commit()
|
session.commit()
|
||||||
except IntegrityError as e:
|
except IntegrityError as e:
|
||||||
logger.warning("Data already exists")
|
|
||||||
session.rollback()
|
session.rollback()
|
||||||
|
logger.warning("Data already exists")
|
||||||
raise DuplicateEntryError("Data already exists in the database") from e
|
raise DuplicateEntryError("Data already exists in the database") from e
|
||||||
except DatabaseError as e:
|
except DatabaseError as e:
|
||||||
session.rollback()
|
session.rollback()
|
||||||
logger.critical("Connection with database interrupted")
|
logger.critical("Connection with database interrupted")
|
||||||
raise DatabaseConnectionError(
|
raise DatabaseConnectionError("Connection with database interrupted") from e
|
||||||
"Connection with database interrupted") from e
|
|
||||||
except SQLAlchemyError as e:
|
except SQLAlchemyError as e:
|
||||||
logger.error(f"An error occured when saving member: {e}")
|
|
||||||
session.rollback()
|
session.rollback()
|
||||||
raise DatabaseError(
|
logger.error(f"An error occurred when saving member: {e}")
|
||||||
"An error occured when creating a new member") from e
|
raise DatabaseError("An error occurred when creating a new member") from e
|
||||||
|
|
||||||
|
def update_member(member: Dict[str, str]):
|
||||||
|
pass
|
||||||
|
|
||||||
__all__ = ["create_new_member"]
|
__all__ = ["create_member", "create_members", "fetch_all_members"]
|
||||||
|
78
src/services/book_overview_service.py
Normal file
78
src/services/book_overview_service.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from typing import Optional, List, Dict
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from xml.dom import minidom
|
||||||
|
from xmlschema import XMLSchema
|
||||||
|
|
||||||
|
from utils.errors import (
|
||||||
|
NoExportEntityError,
|
||||||
|
ExportError,
|
||||||
|
ExportFileError,
|
||||||
|
InvalidContentsError,
|
||||||
|
XsdSchemeNotFoundError,
|
||||||
|
ImportError,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Initialize logger and XML Schema
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
from models import BooksOverview
|
||||||
|
|
||||||
|
from database import fetch_all_book_overviews
|
||||||
|
|
||||||
|
def export_to_xml(file_path: str) -> None:
|
||||||
|
logger.debug("Attempting to export book overview")
|
||||||
|
all_books = fetch_all_book_overviews()
|
||||||
|
|
||||||
|
if not all_books:
|
||||||
|
logger.warning("No books found to export")
|
||||||
|
raise NoExportEntityError("No books found to export")
|
||||||
|
|
||||||
|
xml = overviews_to_xml(all_books)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(file_path, "w", encoding="utf-8") as file:
|
||||||
|
file.write(xml)
|
||||||
|
logger.info("Successfully saved book overview export")
|
||||||
|
except OSError as e:
|
||||||
|
raise ExportFileError("Failed to save to a file") from e
|
||||||
|
|
||||||
|
|
||||||
|
def overviews_to_xml(overview_list: List[BooksOverview]) -> str:
|
||||||
|
root = ET.Element("book_overview")
|
||||||
|
|
||||||
|
for book_overview in overview_list:
|
||||||
|
# Create a <book_entry> element
|
||||||
|
book_element = ET.SubElement(root, "book_entry")
|
||||||
|
|
||||||
|
# Add <title>
|
||||||
|
title_element = ET.SubElement(book_element, "title")
|
||||||
|
title_element.text = book_overview.title
|
||||||
|
|
||||||
|
# Add <author>
|
||||||
|
author_element = ET.SubElement(book_element, "author")
|
||||||
|
author_element.text = book_overview.author_name
|
||||||
|
|
||||||
|
# Add <year_published>
|
||||||
|
year_published_element = ET.SubElement(book_element, "year_published")
|
||||||
|
year_published_element.text = book_overview.year_published
|
||||||
|
|
||||||
|
# Add <isbn>
|
||||||
|
isbn_element = ET.SubElement(book_element, "isbn")
|
||||||
|
isbn_element.text = book_overview.isbn
|
||||||
|
|
||||||
|
# Add <borrower_name>
|
||||||
|
borrower_name = ET.SubElement(book_element, "borrower_name")
|
||||||
|
borrower_name.text = book_overview.borrower_name
|
||||||
|
|
||||||
|
# Add <librarian_name>
|
||||||
|
librarian_name = ET.SubElement(book_element, "librarian_name")
|
||||||
|
librarian_name.text = book_overview.librarian_name
|
||||||
|
|
||||||
|
# Convert the tree to a string
|
||||||
|
tree_str = ET.tostring(root, encoding="unicode")
|
||||||
|
|
||||||
|
# Pretty print the XML
|
||||||
|
pretty_xml = minidom.parseString(tree_str).toprettyxml(indent=(" " * 4))
|
||||||
|
return pretty_xml
|
@ -46,7 +46,7 @@ def export_to_xml(file_path: str) -> None:
|
|||||||
def save_books(books: List[Dict[str, object]]):
|
def save_books(books: List[Dict[str, object]]):
|
||||||
create_books(books)
|
create_books(books)
|
||||||
|
|
||||||
def parse_books_from_xml(file_path: str) -> List[Dict[str, object]]:
|
def parse_from_xml(file_path: str) -> List[Dict[str, object]]:
|
||||||
if not SCHEMA.is_valid(file_path):
|
if not SCHEMA.is_valid(file_path):
|
||||||
raise InvalidContentsError("XML file is not valid according to XSD schema.")
|
raise InvalidContentsError("XML file is not valid according to XSD schema.")
|
||||||
|
|
||||||
|
0
src/services/member_service.py
Normal file
0
src/services/member_service.py
Normal file
@ -23,7 +23,7 @@ class BookEditor(QDialog):
|
|||||||
|
|
||||||
if book:
|
if book:
|
||||||
self.book_id = book.id
|
self.book_id = book.id
|
||||||
self.logger.debug(f"Editing existing book {book.title}")
|
self.logger.debug(f"Editing book {book.title}")
|
||||||
self.create_new = False
|
self.create_new = False
|
||||||
self.fill_with_existing_data(book)
|
self.fill_with_existing_data(book)
|
||||||
else:
|
else:
|
||||||
@ -107,34 +107,29 @@ class BookEditor(QDialog):
|
|||||||
QMessageBox.information(None,
|
QMessageBox.information(None,
|
||||||
"Success",
|
"Success",
|
||||||
"Book updated successfully",
|
"Book updated successfully",
|
||||||
QMessageBox.StandardButton.Ok,
|
QMessageBox.StandardButton.Ok)
|
||||||
QMessageBox.StandardButton.NoButton)
|
|
||||||
|
|
||||||
self.accept()
|
self.accept()
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
QMessageBox.critical(None,
|
QMessageBox.critical(None,
|
||||||
"Invalid Input",
|
"Invalid Input",
|
||||||
f"Input validation failed: {e}",
|
f"Input validation failed: {e}",
|
||||||
QMessageBox.StandardButton.Ok,
|
QMessageBox.StandardButton.Ok)
|
||||||
QMessageBox.StandardButton.NoButton)
|
|
||||||
except DuplicateEntryError as e:
|
except DuplicateEntryError as e:
|
||||||
QMessageBox.critical(None,
|
QMessageBox.critical(None,
|
||||||
"ISBN is already in use",
|
"ISBN is already in use",
|
||||||
"The ISBN provided is already in use",
|
"The ISBN provided is already in use",
|
||||||
QMessageBox.StandardButton.Ok,
|
QMessageBox.StandardButton.Ok)
|
||||||
QMessageBox.StandardButton.NoButton)
|
|
||||||
except DatabaseConnectionError as e:
|
except DatabaseConnectionError as e:
|
||||||
QMessageBox.critical(None,
|
QMessageBox.critical(None,
|
||||||
"Failed to save",
|
"Failed to save",
|
||||||
"Could not connect to the database",
|
"Could not connect to the database",
|
||||||
QMessageBox.StandardButton.Ok,
|
QMessageBox.StandardButton.Ok)
|
||||||
QMessageBox.StandardButton.NoButton)
|
|
||||||
except DatabaseError as e:
|
except DatabaseError as e:
|
||||||
QMessageBox.critical(self.parent,
|
QMessageBox.critical(self.parent,
|
||||||
"An error occurred",
|
"An error occurred",
|
||||||
f"Could not save the book because of the following error: {e}",
|
f"Could not save the book because of the following error: {e}",
|
||||||
QMessageBox.StandardButton.Ok,
|
QMessageBox.StandardButton.Ok)
|
||||||
QMessageBox.StandardButton.NoButton)
|
|
||||||
|
|
||||||
def parse_inputs(self) -> Dict[str, object]:
|
def parse_inputs(self) -> Dict[str, object]:
|
||||||
# Title validation
|
# Title validation
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
from PySide6.QtGui import QGuiApplication, QAction
|
from PySide6.QtGui import QGuiApplication, QAction
|
||||||
from PySide6.QtQml import QQmlApplicationEngine
|
from PySide6.QtQml import QQmlApplicationEngine
|
||||||
@ -7,7 +9,7 @@ from PySide6.QtWidgets import QVBoxLayout, QFormLayout, QLineEdit, QHBoxLayout,
|
|||||||
|
|
||||||
from models import Member
|
from models import Member
|
||||||
|
|
||||||
from database.member import create_new_member
|
from database.member import create_new_member, update_member
|
||||||
|
|
||||||
from utils.errors.database import DatabaseError, DatabaseConnectionError, DuplicateEntryError
|
from utils.errors.database import DatabaseError, DatabaseConnectionError, DuplicateEntryError
|
||||||
|
|
||||||
@ -20,11 +22,12 @@ class MemberEditor(QDialog):
|
|||||||
self.create_layout()
|
self.create_layout()
|
||||||
|
|
||||||
if member:
|
if member:
|
||||||
self.member = member
|
self.member_id = member.id
|
||||||
|
self.logger.debug(f"Editing member {member.first_name} {member.last_name}")
|
||||||
self.fill_with_existing_data()
|
self.fill_with_existing_data()
|
||||||
self.create_new = False
|
self.create_new = False
|
||||||
else:
|
else:
|
||||||
self.member = Member()
|
self.logger.debug("Editing a new member")
|
||||||
self.create_new = True
|
self.create_new = True
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
@ -68,27 +71,79 @@ class MemberEditor(QDialog):
|
|||||||
|
|
||||||
self.layout.addLayout(self.button_layout)
|
self.layout.addLayout(self.button_layout)
|
||||||
|
|
||||||
def fill_with_existing_data(self):
|
def fill_with_existing_data(self, member: Member):
|
||||||
self.first_name_input.setText(self.member.first_name)
|
self.first_name_input.setText(member.first_name)
|
||||||
self.last_name_input.setText(self.member.last_name)
|
self.last_name_input.setText(member.last_name)
|
||||||
self.email_input.setText(self.member.email)
|
self.email_input.setText(member.email)
|
||||||
self.phone_number_input.setText(self.member.phone)
|
self.phone_number_input.setText(member.phone)
|
||||||
|
|
||||||
def save_member(self):
|
def save_member(self):
|
||||||
self.member.first_name = self.first_name_input.text()
|
|
||||||
self.member.last_name = self.last_name_input.text()
|
|
||||||
self.member.email = self.email_input.text()
|
|
||||||
self.member.phone = self.phone_number_input.text()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
member_object = self.parse_inputs()
|
||||||
|
|
||||||
if self.create_new:
|
if self.create_new:
|
||||||
self.logger.debug("Creating new member")
|
create_member(member_object)
|
||||||
create_new_member(self.member)
|
QMessageBox.information(None,
|
||||||
except DuplicateEntryError:
|
"Success",
|
||||||
QMessageBox.critical(None, "Details already in use", "Cannot create a new user",
|
"Member created successfully",
|
||||||
QMessageBox.StandardButton.Ok, QMessageBox.StandardButtons.NoButton)
|
QMessageBox.StandardButton.Ok)
|
||||||
|
else:
|
||||||
|
member_object["id"] = self.member_id
|
||||||
|
update_member(book_object)
|
||||||
|
QMessageBox.information(None,
|
||||||
|
"Success",
|
||||||
|
"Member updated successfully",
|
||||||
|
QMessageBox.StandardButton.Ok)
|
||||||
|
|
||||||
|
|
||||||
|
self.accept()
|
||||||
|
except ValueError as e:
|
||||||
|
QMessageBox.critical(None,
|
||||||
|
"Invalid Input",
|
||||||
|
f"Input validation failed: {e}",
|
||||||
|
QMessageBox.StandardButton.Ok)
|
||||||
|
except DuplicateEntryError as e:
|
||||||
|
QMessageBox.critical(None,
|
||||||
|
"ISBN is already in use",
|
||||||
|
"The ISBN provided is already in use",
|
||||||
|
QMessageBox.StandardButton.Ok)
|
||||||
|
except DatabaseConnectionError as e:
|
||||||
|
QMessageBox.critical(None,
|
||||||
|
"Failed to save",
|
||||||
|
"Could not connect to the database",
|
||||||
|
QMessageBox.StandardButton.Ok)
|
||||||
|
except DatabaseError as e:
|
||||||
|
QMessageBox.critical(self.parent,
|
||||||
|
"An error occurred",
|
||||||
|
f"Could not save the book because of the following error: {e}",
|
||||||
|
QMessageBox.StandardButton.Ok)
|
||||||
|
|
||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
|
def parse_inputs(self) -> Dict:
|
||||||
|
first_name = self.first_name_input.text().strip()
|
||||||
|
if not first_name or len(first_name) > 50:
|
||||||
|
raise ValueError("First name must be non-empty and at most 50 characters long.")
|
||||||
|
|
||||||
|
last_name = self.last_name_input.text().strip()
|
||||||
|
if not last_name or len(last_name) > 50:
|
||||||
|
raise ValueError("Last name must be non-empty and at most 50 characters long.")
|
||||||
|
|
||||||
|
email = self.email_input.text().strip()
|
||||||
|
email_regex = r"^[\w\-\.]+@([\w\-]+\.)+[\w\-]{2,}$"
|
||||||
|
if not re.match(email_regex, email):
|
||||||
|
raise ValueError("E-mail address is not in a valid format.")
|
||||||
|
|
||||||
|
phone_number = self.phone_number_input.text().strip()
|
||||||
|
phone_number_regex = r"(\+\d{1,3})?\d{9}"
|
||||||
|
if not re.match(phone_number_regex, phone_number):
|
||||||
|
raise ValueError("Phone number is not in valid format.")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"first_name": first_name,
|
||||||
|
"last_name": last_name,
|
||||||
|
"email": email,
|
||||||
|
"phone_number": phone_number
|
||||||
|
}
|
||||||
|
|
||||||
__all__ = ["MemberEditor"]
|
__all__ = ["MemberEditor"]
|
||||||
|
@ -7,7 +7,8 @@ from ui.import_preview import PreviewDialog
|
|||||||
from ui.editor import BookEditor, MemberEditor
|
from ui.editor import BookEditor, MemberEditor
|
||||||
|
|
||||||
from utils.errors import ExportError, ExportFileError
|
from utils.errors import ExportError, ExportFileError
|
||||||
from services import book_service
|
from services import book_service, book_overview_service
|
||||||
|
|
||||||
|
|
||||||
class MenuBar(QMenuBar):
|
class MenuBar(QMenuBar):
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
@ -50,23 +51,23 @@ class MenuBar(QMenuBar):
|
|||||||
import_submenu.addAction(import_books_action)
|
import_submenu.addAction(import_books_action)
|
||||||
|
|
||||||
import_members_action = QAction("Import members", self)
|
import_members_action = QAction("Import members", self)
|
||||||
import_members_action.triggered.connect(self.import_data)
|
import_members_action.triggered.connect(self.import_members)
|
||||||
import_submenu.addAction(import_members_action)
|
import_submenu.addAction(import_members_action)
|
||||||
|
|
||||||
# Export submenu
|
# Export submenu
|
||||||
export_submenu = QMenu("Export", self)
|
export_submenu = QMenu("Export", self)
|
||||||
file_menu.addMenu(export_submenu)
|
file_menu.addMenu(export_submenu)
|
||||||
|
|
||||||
export_overview_action = QAction("Export overview", self)
|
|
||||||
export_overview_action.triggered.connect(self.export_data)
|
|
||||||
export_submenu.addAction(export_overview_action)
|
|
||||||
|
|
||||||
export_books_action = QAction("Export books", self)
|
export_books_action = QAction("Export books", self)
|
||||||
export_books_action.triggered.connect(self.export_books)
|
export_books_action.triggered.connect(self.export_books)
|
||||||
export_submenu.addAction(export_books_action)
|
export_submenu.addAction(export_books_action)
|
||||||
|
|
||||||
|
export_overview_action = QAction("Export overview", self)
|
||||||
|
export_overview_action.triggered.connect(self.export_overviews)
|
||||||
|
export_submenu.addAction(export_overview_action)
|
||||||
|
|
||||||
export_members_action = QAction("Export members", self)
|
export_members_action = QAction("Export members", self)
|
||||||
export_members_action.triggered.connect(self.export_data)
|
export_members_action.triggered.connect(self.export_members)
|
||||||
export_submenu.addAction(export_members_action)
|
export_submenu.addAction(export_members_action)
|
||||||
|
|
||||||
file_menu.addSeparator()
|
file_menu.addSeparator()
|
||||||
@ -97,36 +98,34 @@ class MenuBar(QMenuBar):
|
|||||||
def edit_preferences(self):
|
def edit_preferences(self):
|
||||||
SettingsDialog(parent=self).exec()
|
SettingsDialog(parent=self).exec()
|
||||||
|
|
||||||
def export_books(self):
|
def new_book(self):
|
||||||
try:
|
BookEditor().exec()
|
||||||
home_dir = QStandardPaths.writableLocation(
|
self.parent.refresh_book_cards()
|
||||||
QStandardPaths.HomeLocation)
|
|
||||||
file_path, selected_filter = QFileDialog.getSaveFileName(self,
|
|
||||||
"Save book export",
|
|
||||||
home_dir,
|
|
||||||
";;".join(self.file_types.keys()))
|
|
||||||
if file_path:
|
|
||||||
selected_filetype = self.file_types[selected_filter]
|
|
||||||
|
|
||||||
if file_path.endswith(selected_filetype):
|
def new_member(self):
|
||||||
selected_filetype = ""
|
MemberEditor().exec()
|
||||||
|
self.parent.refresh_member_cards()
|
||||||
book_service.export_to_xml(file_path + selected_filetype)
|
|
||||||
|
|
||||||
except ExportFileError as e:
|
|
||||||
QMessageBox.critical(self,
|
|
||||||
"Error saving file",
|
|
||||||
f"Error occurred when saving the exported data: {e}",
|
|
||||||
QMessageBox.StandardButton.Ok,
|
|
||||||
QMessageBox.StandardButton.NoButton)
|
|
||||||
except ExportError as e:
|
|
||||||
QMessageBox.critical(self,
|
|
||||||
"Error exporting books",
|
|
||||||
f"An error occurred when exporting books: {e}",
|
|
||||||
QMessageBox.StandardButton.Ok,
|
|
||||||
QMessageBox.StandardButton.NoButton)
|
|
||||||
|
|
||||||
def import_books(self):
|
def import_books(self):
|
||||||
|
self.import_data("Book", book_service)
|
||||||
|
|
||||||
|
def import_members(self):
|
||||||
|
self.import_data("Member", memb)
|
||||||
|
|
||||||
|
def export_books(self):
|
||||||
|
self.export_data("Book", book_service)
|
||||||
|
|
||||||
|
def export_overviews(self):
|
||||||
|
self.export_data("Book overview", book_overview_service)
|
||||||
|
|
||||||
|
def export_members(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def about(self):
|
||||||
|
QMessageBox.information(
|
||||||
|
self, "About", "Library app demonstrating the phantom read problem")
|
||||||
|
|
||||||
|
def import_data(self, import_name: str, preview_dialog, service):
|
||||||
try:
|
try:
|
||||||
home_dir = QStandardPaths.writableLocation(QStandardPaths.HomeLocation)
|
home_dir = QStandardPaths.writableLocation(QStandardPaths.HomeLocation)
|
||||||
file_path, _ = QFileDialog.getOpenFileName(self, "Choose import file", home_dir, ";;".join(self.file_types.keys()))
|
file_path, _ = QFileDialog.getOpenFileName(self, "Choose import file", home_dir, ";;".join(self.file_types.keys()))
|
||||||
@ -134,18 +133,18 @@ class MenuBar(QMenuBar):
|
|||||||
if not file_path:
|
if not file_path:
|
||||||
return # User canceled
|
return # User canceled
|
||||||
|
|
||||||
books = book_service.parse_books_from_xml(file_path)
|
parsed_data = service.parse_from_xml(file_path)
|
||||||
if not books:
|
if not parsed_data:
|
||||||
QMessageBox.information(self, "No New Books", "No new books to import.", QMessageBox.Ok)
|
QMessageBox.warning(self, f"No New {import_name}s", f"No new {import_name}s to import.", QMessageBox.Ok)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Show preview dialog
|
# Show preview dialog
|
||||||
dialog = PreviewDialog(books, self)
|
dialog = PreviewDialog(parsed_data, self)
|
||||||
if dialog.exec() == QDialog.Accepted:
|
if dialog.exec() == QDialog.Accepted:
|
||||||
# User confirmed, proceed with importing
|
# User confirmed, proceed with importing
|
||||||
book_service.create_books(books)
|
book_service.create_books(parsed_data)
|
||||||
QMessageBox.information(self, "Success", "Books imported successfully!", QMessageBox.Ok)
|
QMessageBox.information(self, "Success", "Books imported successfully!", QMessageBox.Ok)
|
||||||
self.parent.redraw_book_cards()
|
self.parent.refresh_book_cards()
|
||||||
else:
|
else:
|
||||||
QMessageBox.information(self, "Canceled", "Import was canceled.", QMessageBox.Ok)
|
QMessageBox.information(self, "Canceled", "Import was canceled.", QMessageBox.Ok)
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
@ -154,18 +153,28 @@ class MenuBar(QMenuBar):
|
|||||||
f"An error occurred when importing books from the file provided: {e}",
|
f"An error occurred when importing books from the file provided: {e}",
|
||||||
QMessageBox.StandardButton.Ok)
|
QMessageBox.StandardButton.Ok)
|
||||||
|
|
||||||
def new_book(self):
|
def export_data(self, export_name: str, service):
|
||||||
BookEditor().exec()
|
try:
|
||||||
|
home_dir = QStandardPaths.writableLocation(QStandardPaths.HomeLocation)
|
||||||
|
file_path, selected_filter = QFileDialog.getSaveFileName(self,
|
||||||
|
f"Save {export_name} export",
|
||||||
|
home_dir,
|
||||||
|
";;".join(self.file_types.keys()))
|
||||||
|
if file_path:
|
||||||
|
selected_filetype = self.file_types[selected_filter]
|
||||||
|
|
||||||
def new_member(self):
|
if file_path.endswith(selected_filetype):
|
||||||
MemberEditor().exec()
|
selected_filetype = ""
|
||||||
|
|
||||||
def import_data(self):
|
service.export_to_xml(file_path + selected_filetype)
|
||||||
pass
|
|
||||||
|
|
||||||
def export_data(self):
|
except ExportFileError as e:
|
||||||
pass
|
QMessageBox.critical(self,
|
||||||
|
"Error saving file",
|
||||||
def about(self):
|
f"Error occurred when saving the exported data: {e}",
|
||||||
QMessageBox.information(
|
QMessageBox.StandardButton.Ok)
|
||||||
self, "About", "Library app demonstrating the phantom read problem")
|
except ExportError as e:
|
||||||
|
QMessageBox.critical(self,
|
||||||
|
f"Error exporting {export_name}s",
|
||||||
|
f"An error occurred when exporting {export_name}s: {e}",
|
||||||
|
QMessageBox.StandardButton.Ok)
|
||||||
|
@ -44,5 +44,8 @@ class LibraryWindow(QMainWindow):
|
|||||||
# Move the window to the calculated geometry
|
# Move the window to the calculated geometry
|
||||||
self.move(window_geometry.topLeft())
|
self.move(window_geometry.topLeft())
|
||||||
|
|
||||||
def redraw_book_cards(self):
|
def refresh_book_cards(self):
|
||||||
self.dashboard.redraw_cards()
|
self.dashboard.redraw_cards()
|
||||||
|
|
||||||
|
def refresh_member_cards(self):
|
||||||
|
self.member_list.redraw_cards()
|
Loading…
x
Reference in New Issue
Block a user