W ramach projektu stworzona została aplikacja konsolowa implementującą metodę fiszek. Technologie wykorzystane w projekcie to baza danych MongoDB i Python3 z biblioteką mongoengine oraz ncurses.
Pojedyncza fiszka jest tradycyjnie kartą, z zapisanym pytaniem i poprawną odpowiedzią na odwrocie. Z założenia ucząć się tą metodą najpierw próbujemy odpowiedzieć na pytanie, później weryfikując z odpowiedzią. Metoda rozszerzona posiada dodatkowo mechanizm pozwalający na zaplanowanie kolejnego zobaczenia karty, na podstawie tego, czy znaliśmy odpowiedź w ostatniej iteracji oraz jej wcześniejszego stanu (nowa, widziana, opanowana). Stany zmieniają się na podstawie kilku ostatnich odpowiedzi, na poniższych zasadach:
- fiszka dotychczas nie pokazana użytkownikowi jest nowa
- fiszka po udzieleniu przez użytkownika informacji zwrotnej staje się widziana, jeżeli wcześniej była nowa
- fiszka staje się opanowana, jeżeli ostatnie dwie odpowiedzi były pozytywne
- fiszka staje się widziana, jeżeli jest opanowana i została udzielona odpowiedź negatywna
Fiszki mogą być zbierane w talie, czyli inaczej zbiory.
-
prosty system logowania oparty o adres email i hash hasła
-
tworzenie i modyfikacja talii fiszek
-
mechanizm nauki
W pierwszym kroku aplikacja pobiera zestaw fiszek zaplanowanych na dzisiejszy dzień, oraz zestaw nowych kart, jeżeli takie istnieją. Następnie każda z fiszek zostaje pokazana użytkownikowi, który po odkryciu odpowiedzi jest proszony o udzielenie informacji zwrotnej. Jeżeli jest negatywna, fiszka trafia na koniec kolejki, w przeciwnym wypadku zaplanowana na dzień w przyszłości, według reguł zdefiniowanych w zmiennej
FEEDBACK_SETTINGS
. W tym miejscu są również dokonywane zmiany stanów opisane wyżej. -
możliwość udostępniania swoich talii społeczności, ich wyszukiwania i importowania do swojego konta
Talie udostępnione są okrojoną wersją talii użytkownika, poprzez usunięcie informacji związanych z historią nauki, stanem itd. Są ponadto rozszerzeniem, dodając informacje o autorze oraz opis.
Importowanie odbywa się po wyszukaniu talii. Wyszukiwanie odbywa się poprzez sprawdzenie czy zapytanie jest podciągiem nazwy, z pominięciem wielkości znaków. Talia po zaimportowaniu do konta użytkownika zostaje roszerzona o informacje unikalne dla użytkownika i nie różni się niczym od tej utworzonej samodzielnie.
Oryginalny opis projektu przekazany na etapie propozycji znajduje się w pliku pliku [description.md
]
Aplikacja łączy się bezpośrednio z bazą danych.
Do uruchomienia konieczne są poniższe zależności
- Python 3
- mongoengine
- curses
- Uruchomiona lokalnie instancja MongoDB
- System Operacyjny wspierający bibliotekę curses, np. dowolna dystrybucja Linuxa
W celu uruchomienia aplikacji, konieczne jest wywołanie komendy w głównym folderze projektu
python3 main.py
Jeżeli aplikacja zawiesza się przy próbie zalogowania, najprawdopodobniej mongoengine nie jest w stanie połączyć się z bazą danych. Proszę zweryfikować, że na komputerze uruchomiona jest usługa MongoDB i obecny użytkownik ma uprawnienia do korzystania z niej.
Kod domyślne dla mongoengine parametry połączenia z bazą lokalną:
connect('flashcards')
, w niektórych przypadkach może być konieczna modyfikacja
metody połączenia w pliku model/__init__.py
.
Na aplikacje składają się 2 elementy:
- Aplikacja klienta
- Baza danych MongoDB
W projekcie możemy wyróżnić następujące elementy:
- pakiet
model
- model danych bazy danychCard.py
- klasy opisujące pojedynczą fiszkę, w tym:SharedCard
- opisuje fiszkę udostępnioną, występuje jako dokument osadzony w talii udostępnionejPrivateCard
- klasa dziedziczącą po SharedCard, nadająca kontekst konkretnego użytkownika i jego historii. Zawiera logikę modufikacji stanu.
Deck.py
- klasy opisujące talieSharedDeck
- talia udostępniona, zawiera zestaw instancji klasySharedCard
, oraz informacje związane z udostępnianiem talii. Może zostać przekształcona doPrivateDeck
przy importowaniu talii do konta użytkownika.PrivateDeck
- talia prywatna, reprezentująca talię zaimportowaną do konta. Zawiera zestaw instancji klasyPrivateCard
. Odpowiada również za dobór przechowywanych fiszek.
LoginCredentials.py
- model przechowujący dane logowania, oraz kod do logowania i rejestracjiUser.py
- model danych o użytkowniku, w tym talie zaimportowane do jego konta
DeckCreationWizard.py
- klasa pomocnicza przy tworzeniu i edycji talii, przykrywająca niewygodny interfejs zapisu do bazy wynikający z faktu, że obiekty klasyPrivateDeck
są dokumentami osadzonymi.main.py
- główna logika aplikacjiui.py
- funkcje pomocnicze do interfejsu użytkownika, logika wyświetlania
W projekcie wykorzystawana jest biblioteka mongoengine, będąca biblioteką typu ORM, więc struktura bazy danych odpowiada strukturze klas.
Kolekcja login_credentials
(klasa LoginCredentials
)
Przechowuje dane logowania zarejestrowanych użytkowników:
- adres email, wykorzystywany jako identyfikator użytownika
- hash hasła
- informację do którego użytkownika należą dane
Przykładowy dokument:
/* 1 */
{
"_id" : ObjectId("5ee8925b9d621a55e736e151"),
"password_hash" : "0e2355797a60162f3d384568adcaf08e5808adb507042200304a008919f7d5c3",
"email" : "[email protected]",
"user" : ObjectId("5ee8925b9d621a55e736e150")
}
Kolekcja shared_deck
(klasa SharedDeck
)
Przechowuje talie udostępnione przez użytkowników. Każda talia zawiera:
author_id
orazauthor_name
- informacje o autorze, odpowiednio jego id i nazwa użytkownikaname
- nazwę taliidescription
- opis taliicreated
- datę utworzeniacards
- listę fiszek zawartą w talii, instancje klasySharedCard
dc_id
- unikalny identyfikator fiszki w kontekście taliiquestion
- pytanie zawarte w fiszczeanswer
- poprawna odpowiedź na pytanie_cls
- wartośc nieistotna, atrybut wygenerowany automatycznie przez mongoengine, związany z uruchomieniem mechanizmu dziedzienia
Przykładowy dokument:
/* 1 */
{
"_id" : ObjectId("5ee8927b9d621a55e736e152"),
"cards" : [
{
"_cls" : "SharedCard",
"dc_id" : 0,
"question" : "Question 0",
"answer" : "Answer 0"
},
{
"_cls" : "SharedCard",
"dc_id" : 1,
"question" : "Question 1",
"answer" : "Answer 1"
},
{
"_cls" : "SharedCard",
"dc_id" : 2,
"question" : "Question 2",
"answer" : "Answer 2"
},
{
"_cls" : "SharedCard",
"dc_id" : 3,
"question" : "Question 3",
"answer" : "Answer 3"
},
{
"_cls" : "SharedCard",
"dc_id" : 4,
"question" : "Question 4",
"answer" : "Answer 4"
},
{
"_cls" : "SharedCard",
"dc_id" : 5,
"question" : "Question 5",
"answer" : "Answer 5"
}
],
"author_id" : ObjectId("5ee8925b9d621a55e736e150"),
"author_name" : "Daniel",
"name" : "Random new deck",
"description" : "no desc",
"created" : ISODate("2020-06-16T11:35:09.742Z")
}
Kolekcja user
(klasa user
)
Przechowuje informacje przekazywane do klienta po zalogowaniu użytkownika. Każdy dokument jest unikalny dla dokładnie jednego z użytkowników. Zawiera:
username
- nazwę użytkownika do którego się odnosiemail
- adres email użytkownikadecks
- listę talii utworzonych lub zaimportowanych do konta użytkownika. Każdy element listy zawiera:name
- nazwę taliisize
- rozmiarcards
- listę fiszek zawartych w talii, instancje klasyPrivateCard
. Każda z nich może powstać z fiszki przechowywanej w talii współdzielonej i każda zawiera:dc_id
- unikalny numer identyfikacyjny w obrębie taliiquestion
- pytanieanswer
- poprawną odpowiedź na pytaniehistory
- historię nauki fiszki, zawierającą jej stan (wartość atrybutustate
) w momencie nauki oraz wybraną odpowiedźscheduled_for
- infrmację kiedy użytkownik powinien zobaczyć daną fiszkę (jeżeli będzie to możliwe)state
- informacja o aktualnym stanie fiszki. Wartość odnosi się do wartości zmiennych globalnychUNSEEN
,SEEN
iLEARNT
, zdefyniowanych z plikumodel/Card.py
- nieistotny atrybut
_cls
związany z uruchomieniem dziedziczenia w mongoengine
Przykładowy dokument:
/* 1 */
{
"_id" : ObjectId("5ee8925b9d621a55e736e150"),
"username" : "Daniel",
"email" : "[email protected]",
"decks" : [
{
"cards" : [
{
"_cls" : "PrivateCard",
"dc_id" : 0,
"question" : "Question 0",
"answer" : "Answer 0",
"history" : [
{
"state" : 0,
"answer" : "Correct"
}
],
"scheduled_for" : ISODate("2020-06-17T11:37:06.721Z"),
"state" : 1
},
{
"_cls" : "PrivateCard",
"dc_id" : 1,
"question" : "Question 1",
"answer" : "Answer 1",
"history" : [
{
"state" : 0,
"answer" : "Incorrect"
},
{
"state" : 1,
"answer" : "Incorrect"
},
{
"state" : 1,
"answer" : "Correct"
}
],
"scheduled_for" : ISODate("2020-06-18T11:37:15.178Z"),
"state" : 1
},
{
"_cls" : "PrivateCard",
"dc_id" : 2,
"question" : "Question 2",
"answer" : "Answer 2",
"history" : [
{
"state" : 0,
"answer" : "Correct"
}
],
"scheduled_for" : ISODate("2020-06-17T11:37:08.058Z"),
"state" : 1
}
],
"name" : "Random new deck",
"size" : 100
}
]
}