264 lines
8.2 KiB
Python
264 lines
8.2 KiB
Python
from random import choice
|
|
from datetime import date, timedelta
|
|
from flask import flash, session, redirect, url_for, request, render_template
|
|
from sqlalchemy import desc
|
|
from share import share
|
|
from create_db import Card, Rating, get_session
|
|
from settings import get_settings
|
|
"""
|
|
testing
|
|
"""
|
|
def autofill_ratings():
|
|
dbsession = get_session()
|
|
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
|
|
|
|
"""
|
|
Config
|
|
"""
|
|
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, no_factor) * maybe_factor
|
|
elif sorted_rates[0].rating_value == "No":
|
|
sorted_rates.pop(0)
|
|
return calculate_interval(sorted_rates, maybe_factor, no_factor) * no_factor
|
|
elif sorted_rates[0].rating_value == "Delete":
|
|
return -1 #"Deleted"
|
|
|
|
|
|
def get_interval(card_id):
|
|
"""
|
|
takes card_id looks at the history of rates and gives the current interval
|
|
"""
|
|
dbsession = get_session()
|
|
sorted_rates_by_card = dbsession.query(Rating).filter(Rating.card_id == card_id).order_by(desc(Rating.rating_time)).all()
|
|
dbsession.close()
|
|
if sorted_rates_by_card == None:
|
|
print("ni kart... kaj zdaj") #@TODO
|
|
return None
|
|
else:
|
|
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)
|
|
if interval < 0:
|
|
return False
|
|
|
|
last_rating_date = dbsession.query(Rating).filter(Rating.card_id == card_id).order_by(desc(Rating.rating_time)).first()
|
|
if last_rating_date == None:
|
|
dbsession.close()
|
|
return True
|
|
due_date = last_rating_date.rating_time + timedelta(interval)
|
|
dbsession.close()
|
|
return date.today() >= due_date
|
|
|
|
def is_new(card_id):
|
|
dbsession = get_session()
|
|
rating = dbsession.query(Rating).filter(Rating.card_id == card_id).first()
|
|
dbsession.close()
|
|
if rating == None:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
|
|
def list_of_due_cards_by_ids(user_id):
|
|
"this should not include new cards"
|
|
dbsession = get_session()
|
|
cards = dbsession.query(Card).filter(Card.owner_id == user_id).all()
|
|
l = []
|
|
for card in cards:
|
|
if is_new(card.id):
|
|
pass
|
|
elif is_due(card.id):
|
|
l.append(card.id)
|
|
dbsession.close()
|
|
return l
|
|
|
|
|
|
def list_of_new_cards_by_ids(user_id):
|
|
dbsession = get_session()
|
|
cards = dbsession.query(Card).filter(Card.owner_id == user_id).all()
|
|
l = []
|
|
for card in cards:
|
|
rating = dbsession.query(Rating).filter(Rating.card_id == card.id).first()
|
|
if rating == None:
|
|
l.append(card.id)
|
|
dbsession.close()
|
|
return l
|
|
|
|
|
|
def rated_today_by_staus (card_status, user_id):
|
|
"""
|
|
Returns number of cards rated today by user by status (new or due)
|
|
"""
|
|
dbsession = get_session()
|
|
today = date.today()
|
|
|
|
ratings_today = dbsession.query(Rating).filter(
|
|
Rating.rating_time == today,
|
|
Rating.user_id == user_id
|
|
)
|
|
n = 0
|
|
d = 0
|
|
for rating in ratings_today:
|
|
count_all_rates_of_card = dbsession.query(Card).filter(Card.id == rating.card_id).count()
|
|
|
|
if count_all_rates_of_card == 1:
|
|
n+=1
|
|
elif count_all_rates_of_card > 1:
|
|
d+=1
|
|
else:
|
|
print("wtf")
|
|
raise Exception("Count be wrong! There should be at least one rating")
|
|
|
|
dbsession.close()
|
|
if card_status == "new":
|
|
return n
|
|
elif card_status == "due":
|
|
return d
|
|
else:
|
|
raise Exception("must input either 'new' or 'due' as parameter")
|
|
|
|
|
|
def get_a_card_by_status(user_id, card_status):
|
|
if card_status == "new":
|
|
l = list_of_new_cards_by_ids(user_id)
|
|
card_id = l[0]
|
|
if card_status == "due":
|
|
l = list_of_due_cards_by_ids(user_id)
|
|
card_id = l[0]
|
|
return card_id
|
|
|
|
"""
|
|
Export functions
|
|
"""
|
|
def remaining_items(max_items, total_queue, rated_today):
|
|
"""
|
|
gives number of remaining items. Either upto max or if total runs out earlier.
|
|
"""
|
|
n_of_remaining = min((max_items-rated_today), total_queue)
|
|
return n_of_remaining
|
|
|
|
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", user_id)
|
|
rated_due = rated_today_by_staus("due", user_id)
|
|
|
|
total_new = len(list_of_new_cards_by_ids(user_id))
|
|
total_due = len(list_of_due_cards_by_ids(user_id))
|
|
|
|
remaining_new_today = remaining_items(max_new, total_new, rated_new)
|
|
remaining_due_today = remaining_items(max_due, total_due, rated_due)
|
|
remaining_total_today = remaining_due_today + remaining_new_today
|
|
|
|
if remaining_total_today == 0:
|
|
return "done"
|
|
elif rated_due+rated_new == 0:
|
|
return "start"
|
|
else:
|
|
return "continue"
|
|
|
|
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
|
|
"""
|
|
def sr_session():
|
|
dbsession = get_session()
|
|
|
|
#check if user in session
|
|
if not 'user_id' in session:
|
|
redirect(url_for('login'))
|
|
user_id = session['user_id']
|
|
username = session['username']
|
|
|
|
|
|
#form sent?
|
|
if request.method == 'POST':
|
|
#get card_id from the card, rendered from the template, data actually from the template... why tho
|
|
card_id = request.form.get('card_id', None)
|
|
if not card_id:
|
|
raise Exception("card_id necesarry!")
|
|
|
|
#@TODO check if this card is part of the user's deck to prevent possibile hack?
|
|
submit_card = dbsession.query(Card).get(card_id)
|
|
|
|
# Share
|
|
#@@TODO, this should not change the card
|
|
share_request = request.form.get("share", None)
|
|
if share_request:
|
|
share(submit_card, user_id)
|
|
#Rate
|
|
else:
|
|
rate = request.form.get('rate', None)
|
|
if not rate:
|
|
raise Exception("Need rate info!")
|
|
|
|
r = Rating(user_id=user_id, card_id=submit_card.id, rating_value=rate, rating_time=date.today())
|
|
dbsession.add(r)
|
|
dbsession.commit()
|
|
dbsession.close()
|
|
|
|
user_settings = get_settings(user_id)
|
|
max_new = int(user_settings["max_new"])
|
|
max_due = int(user_settings["max_due"])
|
|
|
|
total_new = len(list_of_new_cards_by_ids(user_id))
|
|
total_due = len(list_of_due_cards_by_ids(user_id))
|
|
|
|
rated_today_new = rated_today_by_staus("new", user_id)
|
|
rated_today_due = rated_today_by_staus("due", user_id)
|
|
|
|
remaining_new_today = remaining_items(max_new, total_new, rated_today_new)
|
|
remaining_due_today = remaining_items(max_due, total_due, rated_today_due)
|
|
|
|
print("remaining_new_today: ", remaining_new_today)
|
|
print("remaining_due_today: ", remaining_due_today)
|
|
|
|
#checks if there are any new/due cards left for today and gets the next one.
|
|
#max can be more than all scheduled, min decides which is the limt.
|
|
if remaining_new_today > 0:
|
|
new_card_id=get_a_card_by_status(user_id, "new")
|
|
elif remaining_due_today > 0:
|
|
new_card_id=get_a_card_by_status(user_id, "due")
|
|
else:
|
|
dbsession.close()
|
|
flash("no more cards today")
|
|
return redirect("/menu")
|
|
|
|
show_card = dbsession.query(Card).get(new_card_id)
|
|
interval = get_interval(new_card_id)
|
|
|
|
#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)) |