Compare commits
6 Commits
e4d68ab719
...
8a092c5602
Author | SHA1 | Date |
---|---|---|
Kostanjevec | 8a092c5602 | |
Kostanjevec | ae4077db26 | |
Kostanjevec | a9f2a75442 | |
Kostanjevec | ef1ba946c0 | |
Kostanjevec | e5c44b8714 | |
Kostanjevec | 439a53dc7c |
18
README.md
18
README.md
|
@ -52,27 +52,39 @@ If you and at least one other user rate an **item** with a yes then a match will
|
|||
### Feedback
|
||||
If you have any questions, feedback, ideas or if you would like contribute, please contact us at gia@kompot.si.
|
||||
|
||||
|
||||
## Build instructions
|
||||
Comming soon...
|
||||
|
||||
## TODO
|
||||
### Bugs
|
||||
* email adress bug in matches
|
||||
|
||||
### Design issues
|
||||
#### Sorting and matching
|
||||
The overlap of this features creates some issues. Interest in terms of sorting is likely lost when an item is read, but it may not be lost in terms of matching.
|
||||
* The overlap of this features creates some issues. Interest in terms of sorting is likely lost when an item is read, but it may not be lost in terms of matching.
|
||||
* How to remove cards while still wanting to match on them (absolute interest vs match on "yes")
|
||||
|
||||
### Features
|
||||
#### Links
|
||||
* cards can be links
|
||||
* allow importing of links
|
||||
* db representation of link-cards
|
||||
* display link in iframe or simmilar
|
||||
|
||||
#### Algorithm
|
||||
* SR-algorithm for decks and appropriate db representation
|
||||
* algorithm calculates due cards only with the help of rating history and time of rating.
|
||||
* formula for next interval
|
||||
* algorithm resets on every 'yes' vote.
|
||||
|
||||
### UI
|
||||
* Flash messages should have an approriate color (error is red...)
|
||||
* Visual cue to distinguish shared vs private cards
|
||||
* PDF action to view more than 10 pages.
|
||||
* Fix matches view
|
||||
* Email when at least x cards are due, maybe like x = k max_due
|
||||
* Keyboard support for all actions
|
||||
* scroll PDF
|
||||
* links and buttons
|
||||
|
||||
### Testing
|
||||
* there is no testing.
|
6
app.py
6
app.py
|
@ -1,4 +1,4 @@
|
|||
from flask import Flask, redirect, render_template, session, request, url_for
|
||||
from flask import Flask, redirect, render_template, session, url_for
|
||||
|
||||
from auth import login_required, bp as auth_bp
|
||||
from deck import bp as deck_bp
|
||||
|
@ -7,7 +7,6 @@ from sr_session import sr_session
|
|||
from upload import bp as upload_bp
|
||||
from matches import bp as matches_bp
|
||||
from settings import bp as settings_bp
|
||||
from prob_session import prob_session
|
||||
|
||||
from config import CONFIG
|
||||
|
||||
|
@ -31,8 +30,7 @@ def create_app(test_config=None):
|
|||
|
||||
@app.route('/deck', methods=["GET", "POST"])
|
||||
def deck():
|
||||
return prob_session()
|
||||
#return sr_session()
|
||||
return sr_session()
|
||||
|
||||
@app.route("/share_button", methods=["GET", "POST"])
|
||||
def share_button():
|
||||
|
|
43
menu.py
43
menu.py
|
@ -1,9 +1,8 @@
|
|||
from flask import (
|
||||
Blueprint, flash, redirect, render_template, request, session, url_for
|
||||
)
|
||||
|
||||
from create_db import Deck, Card, get_session
|
||||
from deck import get_deck, probabilistic_deck_generator
|
||||
from create_db import Card, get_session
|
||||
from sr_session import remaining_by_status, schedule_status
|
||||
from settings import get_settings
|
||||
from auth import login
|
||||
|
||||
|
@ -11,7 +10,6 @@ bp = Blueprint('menu', __name__, url_prefix='/menu')
|
|||
|
||||
@bp.route("/", methods=("GET", "POST"))
|
||||
def index():
|
||||
deck_status = []
|
||||
dbsession = get_session()
|
||||
if 'user_id' not in session:
|
||||
return login()
|
||||
|
@ -20,47 +18,21 @@ def index():
|
|||
user_id = session['user_id']
|
||||
username = session['username']
|
||||
print(username)
|
||||
|
||||
old_deck = dbsession.query(Deck).filter(Deck.completed == 0, Deck.owner_id == user_id).all()
|
||||
if old_deck != []:
|
||||
deck_status = "old"
|
||||
status = schedule_status(user_id)
|
||||
remaining_new = remaining_by_status(user_id, "new")
|
||||
remaining_due = remaining_by_status(user_id, "due")-remaining_new
|
||||
|
||||
if request.method == "POST":
|
||||
action = request.form.get("menu", False) #internetna rešitev, nevem kako, ampak dela, tj. dobi info iz meni buttonov
|
||||
print(action)
|
||||
if action == "new_session":
|
||||
old_deck = dbsession.query(Deck).filter(Deck.completed == 0, Deck.owner_id == user_id).all()
|
||||
if old_deck != []:
|
||||
return redirect(url_for("deck"))
|
||||
|
||||
#preverimo če so sploh karte v collectionu
|
||||
print("userID", user_id)
|
||||
c = dbsession.query(Card).filter(Card.owner_id == user_id).all()
|
||||
|
||||
if c == []:
|
||||
print("ne najdem collectiona")
|
||||
return render_template("error/no_cards_in_collection.html", username=username)
|
||||
|
||||
#ustvari novi vnos v Deck
|
||||
user_settings = get_settings(user_id)
|
||||
if user_settings['max_new'] == "0" and user_settings['max_due'] == "0":
|
||||
flash("Error: Attempted to make deck with 0 cards.")
|
||||
return render_template("menu.html")
|
||||
|
||||
deck = probabilistic_deck_generator(user_id, int(user_settings['max_new']), int(user_settings['max_due']))
|
||||
cards_by_id = get_deck(deck)
|
||||
|
||||
if cards_by_id == "":
|
||||
return render_template("error/no_cards_in_collection.html", username=username)
|
||||
else:
|
||||
number_of_cards = len(cards_by_id.split(","))
|
||||
|
||||
print(cards_by_id, number_of_cards)
|
||||
deck = Deck(cards_by_id=cards_by_id, owner_id=user_id, number_of_cards=number_of_cards, current_card=0, completed=False)
|
||||
dbsession.add(deck)
|
||||
dbsession.commit()
|
||||
dbsession.close()
|
||||
|
||||
return redirect(url_for("deck"))
|
||||
elif action == "matches":
|
||||
return redirect(url_for("matches.index"))
|
||||
|
@ -71,8 +43,5 @@ def index():
|
|||
return render_template("settings.html", username=username, user_id=user_id, settings=settings)
|
||||
elif action == "instructions":
|
||||
return render_template("instructions.html", username=username, user_id=user_id)
|
||||
# elif action == "about":
|
||||
# return render_template("about.html", username=username, user_id=user_id)
|
||||
|
||||
|
||||
return render_template("menu.html", username=username, deck_status=deck_status)
|
||||
return render_template("menu.html", username=username, deck_status=status, remaining_due=remaining_due, remaining_new=remaining_new)
|
||||
|
|
|
@ -4,7 +4,10 @@ from share import share
|
|||
|
||||
"""
|
||||
Refactoring the 'deck' function from app.py
|
||||
|
||||
rabi še deck funkcionalnosti, ki so bile prej v menu.py itd...
|
||||
"""
|
||||
|
||||
def prob_session():
|
||||
dbsession = get_session()
|
||||
if not 'user_id' in session:
|
||||
|
@ -92,3 +95,76 @@ def prob_session():
|
|||
|
||||
# Prikaži obrazec
|
||||
return render_template("deck.html", username=username, card=show_card)
|
||||
|
||||
|
||||
|
||||
"""
|
||||
Old menu function
|
||||
|
||||
def index():
|
||||
deck_status = []
|
||||
dbsession = get_session()
|
||||
if 'user_id' not in session:
|
||||
return login()
|
||||
|
||||
if 'user_id' in session:
|
||||
user_id = session['user_id']
|
||||
username = session['username']
|
||||
print(username)
|
||||
|
||||
old_deck = dbsession.query(Deck).filter(Deck.completed == 0, Deck.owner_id == user_id).all()
|
||||
if old_deck != []:
|
||||
deck_status = "old"
|
||||
|
||||
if request.method == "POST":
|
||||
action = request.form.get("menu", False) #internetna rešitev, nevem kako, ampak dela, tj. dobi info iz meni buttonov
|
||||
print(action)
|
||||
if action == "new_session":
|
||||
old_deck = dbsession.query(Deck).filter(Deck.completed == 0, Deck.owner_id == user_id).all()
|
||||
if old_deck != []:
|
||||
return redirect(url_for("deck"))
|
||||
|
||||
#preverimo če so sploh karte v collectionu
|
||||
print("userID", user_id)
|
||||
c = dbsession.query(Card).filter(Card.owner_id == user_id).all()
|
||||
|
||||
if c == []:
|
||||
print("ne najdem collectiona")
|
||||
return render_template("error/no_cards_in_collection.html", username=username)
|
||||
|
||||
#ustvari novi vnos v Deck
|
||||
user_settings = get_settings(user_id)
|
||||
if user_settings['max_new'] == "0" and user_settings['max_due'] == "0":
|
||||
flash("Error: Attempted to make deck with 0 cards.")
|
||||
return render_template("menu.html")
|
||||
|
||||
deck = probabilistic_deck_generator(user_id, int(user_settings['max_new']), int(user_settings['max_due']))
|
||||
cards_by_id = get_deck(deck)
|
||||
|
||||
if cards_by_id == "":
|
||||
return render_template("error/no_cards_in_collection.html", username=username)
|
||||
else:
|
||||
number_of_cards = len(cards_by_id.split(","))
|
||||
|
||||
print(cards_by_id, number_of_cards)
|
||||
deck = Deck(cards_by_id=cards_by_id, owner_id=user_id, number_of_cards=number_of_cards, current_card=0, completed=False)
|
||||
dbsession.add(deck)
|
||||
dbsession.commit()
|
||||
dbsession.close()
|
||||
|
||||
return redirect(url_for("deck"))
|
||||
elif action == "matches":
|
||||
return redirect(url_for("matches.index"))
|
||||
elif action == "upload":
|
||||
return redirect(url_for("upload.index"))
|
||||
elif action == "settings":
|
||||
settings = get_settings(user_id)
|
||||
return render_template("settings.html", username=username, user_id=user_id, settings=settings)
|
||||
elif action == "instructions":
|
||||
return render_template("instructions.html", username=username, user_id=user_id)
|
||||
# elif action == "about":
|
||||
# return render_template("about.html", username=username, user_id=user_id)
|
||||
|
||||
|
||||
return render_template("menu.html", username=username, deck_status=deck_status)
|
||||
"""
|
|
@ -11,29 +11,34 @@ testing
|
|||
def autofill_ratings():
|
||||
dbsession = get_session()
|
||||
for i in range(100):
|
||||
card = Rating(user_id="1", card_id="10", rating_value=choice(["Yes", "Maybe", "No"]), rating_time=date.today()-timedelta(choice([i for i in range(100)])))
|
||||
card = Rating(user_id="1", card_id=choice([10, 13, 14, 75]), rating_value=choice(["Maybe", "No"]), rating_time=date.today()-timedelta(choice([i for i in range(100)])))
|
||||
dbsession.add(card)
|
||||
dbsession.commit()
|
||||
dbsession.close()
|
||||
return None
|
||||
|
||||
autofill_ratings()
|
||||
|
||||
"""
|
||||
Main fuctions
|
||||
Config
|
||||
"""
|
||||
def calculate_interval(sorted_rates):
|
||||
maybe_factor = 1.2
|
||||
no_factor = 2.1
|
||||
|
||||
"""
|
||||
Main fuctions
|
||||
"""
|
||||
def calculate_interval(sorted_rates, maybe_factor, no_factor):
|
||||
if sorted_rates == []:
|
||||
return 1
|
||||
elif sorted_rates[0].rating_value == "Yes":
|
||||
return 1
|
||||
elif sorted_rates[0].rating_value == "Maybe":
|
||||
sorted_rates.pop(0)
|
||||
return calculate_interval(sorted_rates) * maybe_factor
|
||||
return calculate_interval(sorted_rates, maybe_factor, no_factor) * maybe_factor
|
||||
elif sorted_rates[0].rating_value == "No":
|
||||
sorted_rates.pop(0)
|
||||
return calculate_interval(sorted_rates) * no_factor
|
||||
return calculate_interval(sorted_rates, maybe_factor, no_factor) * no_factor
|
||||
elif sorted_rates[0].rating_value == "Delete":
|
||||
return -1 #"Deleted"
|
||||
|
||||
|
@ -49,10 +54,10 @@ def get_interval(card_id):
|
|||
print("ni kart... kaj zdaj") #@TODO
|
||||
return None
|
||||
else:
|
||||
interval = calculate_interval(sorted_rates_by_card)
|
||||
interval = calculate_interval(sorted_rates_by_card, maybe_factor, no_factor)
|
||||
return round(interval)
|
||||
|
||||
|
||||
#to vključuje tudi new...
|
||||
def is_due(card_id):
|
||||
dbsession = get_session()
|
||||
interval = get_interval(card_id)
|
||||
|
@ -67,7 +72,7 @@ def is_due(card_id):
|
|||
return date.today() >= due_date
|
||||
|
||||
|
||||
def list_of_due_card_by_ids(user_id):
|
||||
def list_of_due_cards_by_ids(user_id):
|
||||
dbsession = get_session()
|
||||
cards = dbsession.query(Card).filter(Card.owner_id == user_id).all()
|
||||
l = []
|
||||
|
@ -89,21 +94,8 @@ def list_of_new_cards_by_ids(user_id):
|
|||
dbsession.close()
|
||||
return l
|
||||
|
||||
#obsolete
|
||||
def make_deck(user_id, max_new, max_due):
|
||||
due_cards = list_of_due_card_by_ids(user_id)
|
||||
new_cards = list_of_new_cards_by_ids(user_id)
|
||||
|
||||
due_deck = []
|
||||
due_deck.append(choices(due_cards, k=max_due))
|
||||
|
||||
new_deck = []
|
||||
new_deck.append(choices(new_cards, k=max_new))
|
||||
|
||||
deck = new_deck + due_deck
|
||||
return deck
|
||||
|
||||
|
||||
#TODO sus ker ni user id?
|
||||
def rated_today_by_staus (card_status):
|
||||
"""
|
||||
Returns number of cards rated today by user by status (new or due)
|
||||
|
@ -140,12 +132,48 @@ def get_a_card_by_status(user_id, card_status):
|
|||
card_id = l[0]
|
||||
print(l, "00000000" , card_id)
|
||||
if card_status == "due":
|
||||
l = list_of_due_card_by_ids(user_id)
|
||||
l = list_of_due_cards_by_ids(user_id)
|
||||
card_id = l[0]
|
||||
print(l, "00000000" , card_id)
|
||||
|
||||
return card_id
|
||||
|
||||
"""
|
||||
Export functions
|
||||
"""
|
||||
def schedule_status(user_id):
|
||||
"""
|
||||
Returns information needed for start/continue/done menu ui
|
||||
"""
|
||||
user_settings = get_settings(user_id)
|
||||
max_new = int(user_settings["max_new"])
|
||||
max_due = int(user_settings["max_due"])
|
||||
|
||||
rated_new = rated_today_by_staus("new")
|
||||
rated_due = rated_today_by_staus("due")
|
||||
|
||||
scheduled_new = len(list_of_new_cards_by_ids(user_id))
|
||||
scheduled_due = len(list_of_due_cards_by_ids(user_id))-scheduled_new #TODO ta problem je mogoče še kje...
|
||||
|
||||
max_today_new = min(max_new, scheduled_new+rated_new)
|
||||
max_today_due = min(max_due, scheduled_due+rated_due)
|
||||
|
||||
if rated_due+rated_new == 0:
|
||||
return "start"
|
||||
elif max_today_due+max_today_new > rated_due+rated_new:
|
||||
return "continue"
|
||||
elif max_today_due+max_today_new == rated_due+rated_new:
|
||||
return "done"
|
||||
else:
|
||||
raise Exception("Arithmetic problem with collection // rated too much?")
|
||||
|
||||
def remaining_by_status(user_id, status):
|
||||
if status == "new":
|
||||
l = len(list_of_new_cards_by_ids(user_id))
|
||||
elif status == "due":
|
||||
l = len(list_of_due_cards_by_ids(user_id))
|
||||
return l
|
||||
|
||||
"""
|
||||
Engine
|
||||
"""
|
||||
|
@ -190,7 +218,7 @@ def sr_session():
|
|||
max_due = user_settings["max_due"]
|
||||
|
||||
all_new = len(list_of_new_cards_by_ids(user_id))
|
||||
all_due = len(list_of_due_card_by_ids(user_id))
|
||||
all_due = len(list_of_due_cards_by_ids(user_id))
|
||||
rated_today_new = rated_today_by_staus("new")
|
||||
rated_today_due = rated_today_by_staus("due")
|
||||
|
||||
|
@ -206,5 +234,7 @@ def sr_session():
|
|||
return redirect("/menu")
|
||||
|
||||
show_card = dbsession.query(Card).get(new_card_id)
|
||||
interval = get_interval(new_card_id)
|
||||
|
||||
return render_template("deck.html", username=username, card=show_card)
|
||||
#these factors should be better packaged
|
||||
return render_template("deck.html", username=username, card=show_card, maybe_in=round(interval*maybe_factor), no_in=round(no_factor*interval))
|
|
@ -15,9 +15,9 @@
|
|||
<input type="hidden" name="card_id" value="{{ card['id'] }}">
|
||||
<!-- <span id="buttonContainer" style="display: flex; justify-content: space-around;"> -->
|
||||
<span id="buttonContainer">
|
||||
<button type="submit" name="rate" value="Yes" accesskey="1">Yes</button> <!--ti keyi so alt+shit+key...-->
|
||||
<button type="submit" name="rate" value="Maybe" accesskey="2">Maybe</button>
|
||||
<button type="submit" name="rate" value="No" accesskey="3">No</button>
|
||||
<button type="submit" name="rate" value="Yes" accesskey="1">Yes (1)</button> <!--ti keyi so alt+shit+key...-->
|
||||
<button type="submit" name="rate" value="Maybe" accesskey="2">Maybe ({{maybe_in}})</button>
|
||||
<button type="submit" name="rate" value="No" accesskey="3">No ({{no_in}})</button>
|
||||
<button type="submit" name="rate" value="Delete" accesskey="d">Delete</button>
|
||||
<button type="submit" name="share" value="Share" accesskey="s">Share</button>
|
||||
</span>
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
{% block content %}
|
||||
<main>
|
||||
<form method="post">
|
||||
{% if deck_status == "old" %}
|
||||
<button type="submit" name="menu" value="new_session">Continue</button>
|
||||
{% else %}
|
||||
<button type="submit" name="menu" value="new_session">Start</button>
|
||||
{% if deck_status == "start" %}
|
||||
<button type="submit" name="menu" value="new_session">Start {{remaining_new}}/{{remaining_due}}</button>
|
||||
{% elif deck_status == "continue" %}
|
||||
<button type="submit" name="menu" value="new_session">Continue {{remaining_new}}/{{remaining_due}}</button>
|
||||
{% elif deck_status == "done" %}
|
||||
<button disabled type="submit" name="menu" value="new_session">Start</button>
|
||||
{% endif %}
|
||||
|
||||
<button type="submit" name="menu" value="matches">Matches</button>
|
||||
|
|
Loading…
Reference in New Issue