Misc cli changes #1

Merged
oysteikt merged 5 commits from misc-cli-changes into main 2024-05-17 23:06:35 +02:00
6 changed files with 225 additions and 33 deletions

View File

@ -61,26 +61,6 @@ class WorblehatCli(NumberedCmd):
exit(0) exit(0)
def do_list_bookcases(self, _: str):
bookcase_shelfs = self.sql_session.scalars(
select(BookcaseShelf)
.join(Bookcase)
.order_by(
Bookcase.name,
BookcaseShelf.column,
BookcaseShelf.row,
)
).all()
bookcase_uid = None
for shelf in bookcase_shelfs:
if shelf.bookcase.uid != bookcase_uid:
print(shelf.bookcase.short_str())
bookcase_uid = shelf.bookcase.uid
print(f' {shelf.short_str()} - {sum(i.amount for i in shelf.items)} items')
def do_show_bookcase(self, arg: str): def do_show_bookcase(self, arg: str):
bookcase_selector = InteractiveItemSelector( bookcase_selector = InteractiveItemSelector(
cls = Bookcase, cls = Bookcase,
@ -95,6 +75,35 @@ class WorblehatCli(NumberedCmd):
print(f' {item.name} - {item.amount} copies') print(f' {item.name} - {item.amount} copies')
def do_show_borrowed_queued(self, _: str):
borrowed_items = self.sql_session.scalars(
select(BookcaseItemBorrowing)
.where(BookcaseItemBorrowing.delivered.is_(None))
.order_by(BookcaseItemBorrowing.end_time),
).all()
if len(borrowed_items) == 0:
print('No borrowed items found.')
else:
print('Borrowed items:')
for item in borrowed_items:
print(f'- {item.username} - {item.item.name} - to be delivered by {item.end_time.strftime("%Y-%m-%d")}')
print()
queued_items = self.sql_session.scalars(
select(BookcaseItemBorrowingQueue)
.order_by(BookcaseItemBorrowingQueue.entered_queue_time),
).all()
if len(queued_items) == 0:
print('No queued items found.')
else:
print('Users in queue:')
for item in queued_items:
print(f'- {item.username} - {item.item.name} - entered queue at {item.entered_queue_time.strftime("%Y-%m-%d")}')
def _create_bookcase_item(self, isbn: str): def _create_bookcase_item(self, isbn: str):
bookcase_item = create_bookcase_item_from_isbn(isbn, self.sql_session) bookcase_item = create_bookcase_item_from_isbn(isbn, self.sql_session)
if bookcase_item is None: if bookcase_item is None:
@ -149,6 +158,8 @@ class WorblehatCli(NumberedCmd):
if (existing_item := self.sql_session.scalars( if (existing_item := self.sql_session.scalars(
select(BookcaseItem) select(BookcaseItem)
.where(BookcaseItem.isbn == isbn) .where(BookcaseItem.isbn == isbn)
.join(BookcaseItemBorrowing)
.join(BookcaseItemBorrowingQueue)
).one_or_none()) is not None: ).one_or_none()) is not None:
print(f'\nFound existing item for isbn "{isbn}"') print(f'\nFound existing item for isbn "{isbn}"')
BookcaseItemCli( BookcaseItemCli(
@ -185,11 +196,12 @@ class WorblehatCli(NumberedCmd):
).all() ).all()
if len(slubberter) == 0: if len(slubberter) == 0:
print('No slubberts found. Yay!') print('No slubberts found. Life is good.')
return return
for slubbert in slubberter: for slubbert in slubberter:
print(f'{slubbert.username} - {slubbert.item.name} - {slubbert.end_time.strftime("%Y-%m-%d")}') print('Slubberter:')
print(f'- {slubbert.username} - {slubbert.item.name} - {slubbert.end_time.strftime("%Y-%m-%d")}')
def do_advanced(self, _: str): def do_advanced(self, _: str):
@ -225,20 +237,20 @@ class WorblehatCli(NumberedCmd):
'doc': 'Choose / Add item with its ISBN', 'doc': 'Choose / Add item with its ISBN',
}, },
1: { 1: {
'f': do_list_bookcases,
'doc': 'List all bookcases',
},
2: {
'f': do_search, 'f': do_search,
'doc': 'Search', 'doc': 'Search',
}, },
3: { 2: {
'f': do_show_bookcase, 'f': do_show_bookcase,
'doc': 'Show a bookcase, and its items', 'doc': 'Show a bookcase, and its items',
}, },
3: {
'f': do_show_borrowed_queued,
'doc': 'Show borrowed/queued items',
},
4: { 4: {
'f': do_show_slabbedasker, 'f': do_show_slabbedasker,
'doc': 'Show a slabbedasker, and their wicked ways', 'doc': 'Show slabbedasker',
}, },
5: { 5: {
'f': do_save, 'f': do_save,

View File

@ -58,6 +58,7 @@ class InteractiveItemSelector(Cmd):
self.execute_selection = execute_selection self.execute_selection = execute_selection
self.complete_selection = complete_selection self.complete_selection = complete_selection
self.default_item = default self.default_item = default
self.result = None
if default is not None: if default is not None:
self.prompt = f'Select {cls.__name__} [{default.name}]> ' self.prompt = f'Select {cls.__name__} [{default.name}]> '
@ -197,6 +198,7 @@ class NumberedItemSelector(NumberedCmd):
super().__init__() super().__init__()
self.items = items self.items = items
self.stringify = stringify self.stringify = stringify
self.result = None
self.funcs = { self.funcs = {
i: { i: {
'f': self._select_item, 'f': self._select_item,

View File

@ -91,6 +91,26 @@ class AdvancedOptionsCli(NumberedCmd):
self.sql_session.flush() self.sql_session.flush()
def do_list_bookcases(self, _: str):
bookcase_shelfs = self.sql_session.scalars(
select(BookcaseShelf)
.join(Bookcase)
.order_by(
Bookcase.name,
BookcaseShelf.column,
BookcaseShelf.row,
)
).all()
bookcase_uid = None
for shelf in bookcase_shelfs:
if shelf.bookcase.uid != bookcase_uid:
print(shelf.bookcase.short_str())
bookcase_uid = shelf.bookcase.uid
print(f' {shelf.short_str()} - {sum(i.amount for i in shelf.items)} items')
def do_done(self, _: str): def do_done(self, _: str):
return True return True
@ -104,6 +124,10 @@ class AdvancedOptionsCli(NumberedCmd):
'f': do_add_bookcase_shelf, 'f': do_add_bookcase_shelf,
'doc': 'Add bookcase shelf', 'doc': 'Add bookcase shelf',
}, },
3: {
'f': do_list_bookcases,
'doc': 'List all bookcases',
},
9: { 9: {
'f': do_done, 'f': do_done,
'doc': 'Done', 'doc': 'Done',

View File

@ -1,4 +1,4 @@
from datetime import datetime from datetime import datetime, timedelta
from textwrap import dedent from textwrap import dedent
from sqlalchemy import select from sqlalchemy import select
@ -7,6 +7,7 @@ from sqlalchemy.orm import Session
from worblehat.cli.prompt_utils import ( from worblehat.cli.prompt_utils import (
InteractiveItemSelector, InteractiveItemSelector,
NumberedCmd, NumberedCmd,
NumberedItemSelector,
format_date, format_date,
prompt_yes_no, prompt_yes_no,
) )
@ -22,6 +23,7 @@ from worblehat.services.bookcase_item import (
create_bookcase_item_from_isbn, create_bookcase_item_from_isbn,
is_valid_isbn, is_valid_isbn,
) )
from worblehat.services.config import Config
from .bookcase_shelf_selector import select_bookcase_shelf from .bookcase_shelf_selector import select_bookcase_shelf
@ -174,6 +176,50 @@ class BookcaseItemCli(NumberedCmd):
print(f'Successfully delivered the item for {borrowing.username}') print(f'Successfully delivered the item for {borrowing.username}')
def do_extend_borrowing(self, _: str):
borrowings = self.sql_session.scalars(
select(BookcaseItemBorrowing)
.join(BookcaseItem, BookcaseItem.uid == BookcaseItemBorrowing.fk_bookcase_item_uid)
.where(BookcaseItem.isbn == self.bookcase_item.isbn)
.order_by(BookcaseItemBorrowing.username)
).all()
if len(borrowings) == 0:
print('No one seems to have borrowed this item')
return
borrowing_queue = self.sql_session.scalars(
select(BookcaseItemBorrowingQueue)
.where(
BookcaseItemBorrowingQueue.item == self.bookcase_item,
BookcaseItemBorrowingQueue.item_became_available_time == None,
)
.order_by(BookcaseItemBorrowingQueue.entered_queue_time)
).all()
if len(borrowing_queue) != 0:
print('Sorry, you cannot extend the borrowing because there are people waiting in the queue')
print('Borrowing queue:')
for i, b in enumerate(borrowing_queue):
print(f' {i + 1}) {b.username}')
return
print('Who are you?')
selector = NumberedItemSelector(
items = list(borrowings),
stringify = lambda b: f'{b.username} - Until {format_date(b.end_time)}',
)
selector.cmdloop()
if selector.result is None:
return
borrowing = selector.result
borrowing.end_time = datetime.now() + timedelta(days=int(Config['deadline_daemon.days_before_queue_position_expires']))
self.sql_session.flush()
print(f'Successfully extended the borrowing for {borrowing.username} until {format_date(borrowing.end_time)}')
def do_done(self, _: str): def do_done(self, _: str):
return True return True
@ -188,10 +234,14 @@ class BookcaseItemCli(NumberedCmd):
'doc': 'Deliver', 'doc': 'Deliver',
}, },
3: { 3: {
'f': do_extend_borrowing,
'doc': 'Extend borrowing',
},
4: {
'f': do_edit, 'f': do_edit,
'doc': 'Edit', 'doc': 'Edit',
}, },
4: { 5: {
'f': do_update_data, 'f': do_update_data,
'doc': 'Pull updated data from online databases', 'doc': 'Pull updated data from online databases',
}, },

View File

@ -13,6 +13,7 @@ class SearchCli(NumberedCmd):
def __init__(self, sql_session: Session): def __init__(self, sql_session: Session):
super().__init__() super().__init__()
self.sql_session = sql_session self.sql_session = sql_session
self.result = None
def do_search_all(self, _: str): def do_search_all(self, _: str):
@ -57,11 +58,11 @@ class SearchCli(NumberedCmd):
elif len(author) == 1: elif len(author) == 1:
selected_author = author[0] selected_author = author[0]
print('Found author:') print('Found author:')
print(f" {selected_author.name} ({sum(item.amount for item in selected_author.books)} items)") print(f" {selected_author.name} ({sum(item.amount for item in selected_author.items)} items)")
else: else:
selector = NumberedItemSelector( selector = NumberedItemSelector(
items = author, items = author,
stringify = lambda author: f"{author.name} ({sum(item.amount for item in author.books)} items)", stringify = lambda author: f"{author.name} ({sum(item.amount for item in author.items)} items)",
) )
selector.cmdloop() selector.cmdloop()
if selector.result is None: if selector.result is None:
@ -69,7 +70,7 @@ class SearchCli(NumberedCmd):
selected_author = selector.result selected_author = selector.result
selector = NumberedItemSelector( selector = NumberedItemSelector(
items = selected_author.books, items = list(selected_author.items),
stringify = lambda item: f"{item.name} ({item.isbn})", stringify = lambda item: f"{item.name} ({item.isbn})",
) )
selector.cmdloop() selector.cmdloop()

View File

@ -1,4 +1,5 @@
import csv import csv
from datetime import datetime, timedelta
from pathlib import Path from pathlib import Path
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
@ -6,7 +7,11 @@ from sqlalchemy.orm import Session
from worblehat.flaskapp.database import db from worblehat.flaskapp.database import db
from ..models import ( from ..models import (
Author,
Bookcase, Bookcase,
BookcaseItem,
BookcaseItemBorrowing,
BookcaseItemBorrowingQueue,
BookcaseShelf, BookcaseShelf,
Language, Language,
MediaType, MediaType,
@ -117,6 +122,100 @@ def seed_data(sql_session: Session = db.session):
BookcaseShelf(row=0, column=4, bookcase=bookcases[4], description="Religion"), BookcaseShelf(row=0, column=4, bookcase=bookcases[4], description="Religion"),
] ]
authors = [
Author(name="Donald E. Knuth"),
Author(name="J.K. Rowling"),
Author(name="J.R.R. Tolkien"),
Author(name="George R.R. Martin"),
Author(name="Stephen King"),
Author(name="Agatha Christie"),
]
book1 = BookcaseItem(
name = "The Art of Computer Programming",
isbn = "9780201896831",
)
book1.authors.add(authors[0])
book1.media_type = media_types[0]
book1.shelf = shelfs[59]
book2 = BookcaseItem(
name = "Harry Potter and the Philosopher's Stone",
isbn = "9780747532743",
)
book2.authors.add(authors[1])
book2.media_type = media_types[0]
book2.shelf = shelfs[-1]
book_owned_by_other_user = BookcaseItem(
name = "Book owned by other user",
isbn = "9780747532744",
)
book_owned_by_other_user.owner = "other_user"
book_owned_by_other_user.authors.add(authors[4])
book_owned_by_other_user.media_type = media_types[0]
book_owned_by_other_user.shelf = shelfs[-2]
borrowed_book_more_available = BookcaseItem(
name = "Borrowed book with more available",
isbn = "9780747532745",
)
borrowed_book_more_available.authors.add(authors[5])
borrowed_book_more_available.media_type = media_types[0]
borrowed_book_more_available.shelf = shelfs[-3]
borrowed_book_more_available.amount = 2
borrowed_book_no_more_available = BookcaseItem(
name = "Borrowed book with no more available",
isbn = "9780747532746",
)
borrowed_book_no_more_available.authors.add(authors[5])
borrowed_book_no_more_available.media_type = media_types[0]
borrowed_book_no_more_available.shelf = shelfs[-3]
borrowed_book_people_in_queue = BookcaseItem(
name = "Borrowed book with people in queue",
isbn = "9780747532747",
)
borrowed_book_people_in_queue.authors.add(authors[5])
borrowed_book_people_in_queue.media_type = media_types[0]
borrowed_book_people_in_queue.shelf = shelfs[-3]
borrowed_book_by_slabbedask = BookcaseItem(
name = "Borrowed book by slabbedask",
isbn = "9780747532748",
)
borrowed_book_by_slabbedask.authors.add(authors[5])
borrowed_book_by_slabbedask.media_type = media_types[0]
borrowed_book_by_slabbedask.shelf = shelfs[-3]
books = [
book1,
book2,
book_owned_by_other_user,
borrowed_book_more_available,
borrowed_book_no_more_available,
borrowed_book_people_in_queue,
]
slabbedask_borrowing = BookcaseItemBorrowing(
username="slabbedask",
item=borrowed_book_more_available,
)
slabbedask_borrowing.end_time = datetime.now() - timedelta(days=1)
borrowings = [
BookcaseItemBorrowing(username="user", item=borrowed_book_more_available),
BookcaseItemBorrowing(username="user", item=borrowed_book_no_more_available),
BookcaseItemBorrowing(username="user", item=borrowed_book_people_in_queue),
slabbedask_borrowing,
]
queue = [
BookcaseItemBorrowingQueue(username="user", item=borrowed_book_people_in_queue),
]
with open(Path(__file__).parent.parent.parent / 'data' / 'iso639_1.csv') as f: with open(Path(__file__).parent.parent.parent / 'data' / 'iso639_1.csv') as f:
reader = csv.reader(f) reader = csv.reader(f)
languages = [Language(name, code) for (code, name) in reader] languages = [Language(name, code) for (code, name) in reader]
@ -125,5 +224,9 @@ def seed_data(sql_session: Session = db.session):
sql_session.add_all(bookcases) sql_session.add_all(bookcases)
sql_session.add_all(shelfs) sql_session.add_all(shelfs)
sql_session.add_all(languages) sql_session.add_all(languages)
sql_session.add_all(authors)
sql_session.add_all(books)
sql_session.add_all(borrowings)
sql_session.add_all(queue)
sql_session.commit() sql_session.commit()
print("Added test media types, bookcases and shelfs.") print("Added test media types, bookcases and shelfs.")