Książka kontaktowa - z zapisywaniem kontaktów do pliku i wydzieloną reużywalną funkcją

Książka kontaktowa - z zapisywaniem kontaktów do pliku i wydzieloną reużywalną funkcją
Photo by Brett Jordan / Unsplash
"""
Książka kontaktowa
Naszym zadaniem jest przygotowanie działającej w terminalu aplikacji przechowującej dane kontaktowe.
Na tym etapie przyjmujemy, że nazwy kontaktu ( imie z nazwiskiem, pseudonim etc) są unikalne -
możemy więc użyć ich jako kluczy w słowniku. Sugerowana struktura danych wyglądałaby tak:
kontakty = {
"Bob" : "[email protected]",
"Ada" : "FB_id: 78934759834",
}
Podstawa
W opcji minimum powinniśmy przygotować interfejs tekstowy działający w pętli nieskończonej. W tej
postaci nie musi on jeszcze czegokolwiek innego robić - ma się jedynie poprawnie wyświetlać i dawać
użytkownikowi szansę na wpisanie wyboru.
Wersja 1
W pierwszej wersji funkcjonalnej należy dodać możliwość dodawania kontaktów i wydruk wszystkich
kontaktów.
Wersja 2
Następnym krokiem byłoby dodanie pozostałej funkcjonalności - w większości będzie ona bazowała
na tym co jest w wersji 1. Na tym etapie mamy tzw. MVP - minimum viable product.
Wersja 3
Mając bazowy produkt warto się zastanowić co może pójść w trakcie korzystania z aplikacji nie tak.
Warto obsłużyć takie sytuacje - np. gdy użytkownik spróbuje usunąć kontakt który nie istnieje należy
to sprawdzić - i jeśli faktycznie kontaktu nie ma wyświetlić odpowiedni komunikat bez podejmowania
próby usunięcia wpisu (co “wywaliłoby” nasz program).
Kosmetyka
Tu możemy się zająć tym jak wyświetlić poszczególne wybory menu w bardziej przyjazny dla odbiorcy
sposób np. wybierając opcję “Wyświetl całą książkę z kontaktami” fajnie jeśli użytkownik otrzyma nie
po prostu wydruk słownika, tylko np. nazwę, poniżej danej kontaktowe, poniżej jakieś rozdzielenie (np.
serię *), po czym następny kontakt.

kontakty = {
"Bob" : "[email protected]",
"Ada" : "FB_id: 78934759834",
}

Przechowywanie kontaktów
W naszej aplikacji do kontaktów dodajcie pozycje menu do wczytywania książki z pliku i zapisywanie
do niego.
Nie kombinujcie z trybem “a” - czyli append. Wczytujcie całą zawartość pliku w trybie “r” i z pomocą
biblioteki json zamieniajcie ją na obiekt z którego możecie korzystać w Pythonie (zakładam, że jest to
słownik).
Z kolei przy zapisie danych nadpisujcie cały plik zaktualizowaną zawartością (czyli skorzystajcie z trybu
“w”).
Pomyślcie nad dodaniem automatycznego wczytania kontaktów przy starcie aplikacji. Z kolei przy jej
zamykaniu może warto zapytać osoby z niej korzystającej czy chce zapisać zmiany?

"""
import json
import os

SCIEZKA_FOLDERU = "data"
SCIEZKA_PLIKU = os.path.join(SCIEZKA_FOLDERU, "kontakty.json")

# czy folder istnieje?
os.makedirs(SCIEZKA_FOLDERU, exist_ok=True)


# jesli plik nie istnieje tworzymy go z pustym slownikiem
if not os.path.exists(SCIEZKA_PLIKU):
    with open(SCIEZKA_PLIKU, "w", encoding="utf-8") as f:
        json.dump({}, f, ensure_ascii=False, indent=4)

# ladujemy dane z pliku do zmiennej 'kontakty':
with open(SCIEZKA_PLIKU, "r", encoding="utf-8") as f:
    try:
        kontakty = json.load(f)
    except json.JSONDecodeError:
        kontakty = {}

def zapisz_kontakty():
    with open(SCIEZKA_PLIKU, "w", encoding="utf-8") as f:
        json.dump(kontakty, f, ensure_ascii=False, indent=4)

while True:
    print()
    print("Wybierz operację do wykonania:")
    print("         1 - dopisanie pozycji do książki")
    print("         2 - aktualizacja pozycji książki")
    print("         3 - usunięcie pozycji książki")
    print("         4 - wydruk imion z książki")
    print("         5 - wydruk całej książki z kontaktami")
    print("         6 - koniec programu")
    wybor = input("Podaj kod operacji = ")

    if wybor == "6":
        wybor = input("Jeśli chcesz zapisać zmiany i wyjść z programu wybierz 't': ")
        if wybor == 't':
            zapisz_kontakty()
            print()
            print("Zapisano zmiany i zamknieto program.")
        break
    elif wybor == "1":
        nazwa_kontaktu = input("Podaj nazwę kontaktu: ").strip()
        if nazwa_kontaktu in kontakty:
            print("Podany kontakt już istnieje. Użyj opcji aktualizacji!")
        else:
            dane_kontaktu = input("Podaj dane kontaktowe, np.numer telefonu, adres email: ").strip()
            kontakty[nazwa_kontaktu] = dane_kontaktu
            zapisz_kontakty()

            print(f"Kontakt {nazwa_kontaktu} o danych {dane_kontaktu} został dodany do listy kontaktów!")
            print()
            print(f"Obecnie w książce kontaktowej jest {len(kontakty)} kontaktów.")
    elif wybor == "2":
        print("Aktualizacja pozycji książki")
        aktualizacja_pozycji = input("Jeśli chcesz zaktualizować nazwę, pod którą jest zapisany kontakt wciśnij 'n'. Jeśli chcesz zaktualizować dane kontaktu wcisnij 'd'.").strip().lower()
        if aktualizacja_pozycji == "n":
            print("Aktualizujemy nazwę kontaktu.")
            stara_nazwa = input("Podaj nazwę kontaktu do zmiany: ").strip()
            znaleziony_kontakt = None
            for nazwa in kontakty:
                if nazwa.lower() == stara_nazwa.lower():
                    znaleziony_kontakt = nazwa
                    break
            if not znaleziony_kontakt:
                print(f"Kontakt o podanej nazwie {stara_nazwa} nie istnieje!")
            else:
                nowa_nazwa = ''
                while not nowa_nazwa:
                    nowa_nazwa = input("Podaj nową nazwę: ").strip()
                    if not nowa_nazwa:
                        print("Nowa nazwa nie może być pusta! Podaj nową nazwę.")
                if nowa_nazwa in kontakty:
                    print(f"Kontakt o nazwie {nowa_nazwa} już istnije!")
                else:
                    kontakty[nowa_nazwa] = kontakty.pop(znaleziony_kontakt)
                    zapisz_kontakty()

                    print(f"Nazwa kontaktu {znaleziony_kontakt} została zastąpiona przez {nowa_nazwa}")
        elif aktualizacja_pozycji == "d":
            print("Aktualizujemy dane kontaktu.")
            szukany_kontakt = input("Podaj nazwę kontaktu, którego dane chcesz zaktualizować: ").strip()

            znaleziony_kontakt = None
            for nazwa_k in kontakty:
                if nazwa_k.lower() == szukany_kontakt.lower():
                    znaleziony_kontakt = nazwa_k
                    break
            if not znaleziony_kontakt:
                print(f"Kontakt o podanej nazwie {szukany_kontakt} nie istnieje!")
            else:
                potwierdzenie_aktualizacji = input(f"Obecne dane kontaktowe: {kontakty[znaleziony_kontakt]}. Na pewno chcesz je zaktualizować? Jeśli tak wcisnij 't', jeśli nie, wciśnij 'n'.").strip().lower()
                if potwierdzenie_aktualizacji == 't':
                    nowe_dane = ''
                    while not nowe_dane:
                        print(f"Aktualizujemy dane kontaktu: {kontakty[znaleziony_kontakt]}")
                        nowe_dane = input("Podaj nowe dane: ").strip()
                        if not nowe_dane:
                            print("Dane kontaktowe nie mogą być puste! Spróbuj ponownie.")
                
                    kontakty[znaleziony_kontakt] = nowe_dane
                    zapisz_kontakty()

                    print(f"Dane kontaktowe kontaktu '{znaleziony_kontakt}' zostały zaktualizowane.")
                else:
                    print("Rezygnacja z aktualizacji danych. Powrót do menu głównego.")
        else:
            print("Nieprawidlowy wybór opcji. Wpisz 'n' (chcę zaktualizować nazwę kontaktu) albo 'd' (chcę zaktualizowac dane kontaktu)")
    elif wybor == "3":
        if not kontakty:
            print("Książka kontaktowa jest pusta!")
        else:
            kontakt_do_usuniecia = input("Podaj nazwę kontaktu, który chcesz usunąć: ").strip()
            znaleziony_kontakt = None
            for nazwa in kontakty:
                if nazwa.lower() == kontakt_do_usuniecia.lower():
                    znaleziony_kontakt = nazwa
                    break
            if not znaleziony_kontakt:
                print(f"Podany kontakt, {kontakt_do_usuniecia} nie istnieje! Upewnij się, że wpisaleś poprawną nazwę. ")
            else:
                potwierdzenie_usuniecia = input(f"Czy na pewno chcesz usunąć kontakt '{znaleziony_kontakt}'? (t/n): ").strip().lower()
                if potwierdzenie_usuniecia == "t":
                    dane_do_usuniecia = kontakty.pop(znaleziony_kontakt)
                    zapisz_kontakty()

                    # del kontakty[znaleziony_kontakt] del usuwa kontakt i nie mozna juz nic z tym zrobic! 
                    # .pop() usuwa kontakt i można go np. pokazać użytkownikowi, zapisać w logu albo przywrócić, jeśli ktoś się rozmyśli
                    print(f"Kontakt '{znaleziony_kontakt}': {dane_do_usuniecia} został usunięty.")
                else:
                    print("Usunięcie anulowane. Powrót do menu głównego.")
    elif wybor == "4":
        print("=============== Imiona w książce kontaktowej: ==============")
        if not kontakty:
            print("Książka kontaktowa jest pusta!")
        else:
            print(f"Liczba imion w książce: {len(kontakty)}")
            for i, key in enumerate(sorted(kontakty), start=1):
                print(f"{i}. {key}")
    elif wybor == "5":
        if not kontakty:
            print("Książka kontaktowa jest pusta!")
        else:
            print("Książka kontaktowa zawiera: ")
            for nazwa_kontaktu, dane_kontaktu in kontakty.items():
                print(f"Nazwa: {nazwa_kontaktu}") 
                print(f"Dane kontaktu: {dane_kontaktu}.")
                print("*" * 30)
    else:
        print("Ups, coś poszlo nie tak!")