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, get_engine from settings import get_settings from link_handler import render_embed_link """ testing """ def autofill_ratings(): Session = get_session() with Session() as dbsession: 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() get_engine().dispose() 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 """ Session = get_session() with Session() as dbsession: sorted_rates_by_card = dbsession.query(Rating).filter(Rating.card_id == card_id).order_by(desc(Rating.rating_time)).all() dbsession.close() get_engine().dispose() 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): Session = get_session() with Session() as dbsession: interval = get_interval(card_id) last_rating_date = dbsession.query(Rating).filter(Rating.card_id == card_id).order_by(desc(Rating.rating_time)).first() due_date = last_rating_date.rating_time + timedelta(interval) dbsession.close() get_engine().dispose() if interval < 0: return False if last_rating_date == None: return True return date.today() >= due_date def is_new(card_id): Session = get_session() with Session() as dbsession: rating = dbsession.query(Rating).filter(Rating.card_id == card_id).first() dbsession.close() get_engine().dispose() return rating == None def list_of_due_cards_by_ids(user_id): "this should not include new cards" Session = get_session() with Session() as dbsession: 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() get_engine().dispose() return l def list_of_new_cards_by_ids(user_id): Session = get_session() with Session() as dbsession: 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) """ n = 0 d = 0 today = date.today() Session = get_session() with Session() as dbsession: ratings_today = dbsession.query(Rating).filter( Rating.rating_time == today, Rating.user_id == user_id ) for rating in ratings_today: count_all_rates_of_card = dbsession.query(Rating).filter(rating.card_id == Rating.card_id).count() print("count_all_rates_of_card: ", count_all_rates_of_card) 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() get_engine().dispose() 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(): #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? Session = get_session() with Session() as dbsession: 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() get_engine().dispose() 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) print("list_of_due_cards_by_ids: ", list_of_due_cards_by_ids(user_id)) print("list_of_new_cards_by_ids: ", list_of_new_cards_by_ids(user_id)) #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: print("gettin new") ##TODO problem je, ker na produkciji zgleda kot da jemlje skoz new, čeprav bi moral due next_card_id=get_a_card_by_status(user_id, "new") elif remaining_due_today > 0: print("getting due") next_card_id=get_a_card_by_status(user_id, "due") else: flash("no more cards today") return redirect("/menu") Session = get_session() with Session() as dbsession: show_card = dbsession.query(Card).get(next_card_id) dbsession.close() get_engine().dispose() interval = get_interval(next_card_id) card_type = show_card.card_type print("card type: ", card_type) if card_type == 'PDF' or card_type== None: #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)) elif card_type == 'URL': #templates for different kinds of links return render_embed_link(cm_username=username, card=show_card, maybe_in=round(interval*maybe_factor), no_in=round(no_factor*interval)) #return render_template("link.html", username=username, card=show_card, maybe_in=round(interval*maybe_factor), no_in=round(no_factor*interval))