nov db idiom. funkcije za prikazovanje in importanje linkov

master
janko 2023-08-27 18:52:59 +02:00
parent be6a3242f9
commit 53e7b17e1c
15 changed files with 495 additions and 341 deletions

2
app.py
View File

@ -3,11 +3,11 @@ 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
from menu import bp as menu_bp
from sr_session import sr_session
from upload import bp as upload_bp
from import_link import bp as import_link_bp
from matches import bp as matches_bp
from settings import bp as settings_bp
from sr_session import sr_session
from config import CONFIG

10
auth.py
View File

@ -4,15 +4,16 @@ from flask import (
Blueprint, flash, g, redirect, render_template, request, session, url_for
)
from hashlib import md5
from create_db import User, get_session
from create_db import User, get_session, get_engine
from share import get_all_shared
bp = Blueprint('auth', __name__, url_prefix='/auth')
@bp.route('/register', methods=('GET', 'POST'))
def register():
dbsession = get_session()
Session = get_session()
with Session() as dbsession:
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
@ -52,6 +53,7 @@ def register():
return redirect(url_for("auth.login"))
flash(error)
get_engine().dispose()
return render_template('register.html')
@ -59,8 +61,9 @@ def register():
@bp.route('/login', methods=('GET', 'POST'))
def login():
if request.method == 'POST':
dbsession = get_session()
Session = get_session()
with Session() as dbsession:
username = request.form['username']
password = request.form['password']
error = None
@ -79,6 +82,7 @@ def login():
return redirect(url_for("menu.index")) #TODO ne dela
flash(error)
get_engine().dispose()
return render_template('login.html')

View File

@ -47,10 +47,44 @@ class Rating(Base):
engine = create_engine(CONFIG['DB_CONNECTION'])
Base.metadata.create_all(engine)
def create_all():
Base.metadata.create_all(Engine)
Engine = create_engine(CONFIG['DB_CONNECTION'])
Session = sessionmaker(Engine)
def get_session():
# Engine je samo enkrat treba inicializirat, se mi zdi.
# engine = create_engine(CONFIG['DB_CONNECTION'])
dbsessionmaker = sessionmaker(bind=engine)
return dbsessionmaker()
return Session
def get_engine():
return Engine
"""
NAVODILA TODO
Upravljanje klicev na bazo
Base = declarative_base()
class ImeTabele(Base):
__tablename__ = 'imetabele'
stolpec = Column(Tip, druge lastnosti stolpca)
def create_all():
Base.metadata.create_all(Engine)
Ustvarimo engine in session objekt ter funkciji, ki ju vračata
Engine = create_engine(CONFIG['DB_CONNECTION'])
Session = sessionmaker(Engine)
def get_session():
return Session
def get_engine():
return Engine
V skripti, ki želi dostopati pa do baze pa klic postavimo v naslednji okvir:
Session = get_session()
with Session() as session:
<vsebina klica>
get_engine().dispose()
"""

View File

@ -3,7 +3,7 @@ from flask import (
Blueprint, g, session
)
from auth import login_required
from create_db import Card, User, get_session
from create_db import Card, User, get_session, get_engine
from numpy.random import choice
@ -11,8 +11,12 @@ bp = Blueprint('deck', __name__)
@bp.route('/deck', methods=['GET'])
def get_collection(user_id):
dbsession = get_session()
Session = get_session()
with Session() as dbsession:
c = dbsession.query(Card).filter(Card.owner_id == user_id).all()
dbsession.close()
get_engine().dispose()
return c

View File

@ -1,8 +1,11 @@
from flask import (
Blueprint, render_template, request, session, flash
)
from create_db import Card, get_session
from link_handler import check_response
from create_db import Card, get_session, get_engine
from link_handler import check_link
from werkzeug.utils import secure_filename
import tempfile
import os
bp = Blueprint('import_link', __name__, url_prefix='/import_link')
@ -19,28 +22,34 @@ def import_link():
username = session['username']
user_id = session['user_id']
if request.method == 'POST':
import_type = request.form.get("import_type", False)
print(import_type)
import_type = request.form.get("import_txt")
print("###########################", import_type)
if import_type == "import_txt":
print("!2313232321")
return render_template("import_txt.html", user_id=user_id, username=username)
else:
link = request.form.get("link", False)
if check_response(link) == 1:
print(link, 'is ok')
link = request.form.get("import_link", False)
commit_link(link=link, user_id=user_id)
else:
print(link, 'is not ok')
return render_template("import_link.html", user_id=user_id, username=username)
def commit_link(link, user_id):
dbsession = get_session()
Session = get_session()
with Session() as dbsession:
existing_link = dbsession.query(Card).filter_by(owner_id=user_id, item_location=link).first()
if existing_link:
flash(f"{link} has already been imported.")
print(f"{link} has already been imported.")
flash(f"{link} has already been imported.","error")
return -1
link_check = check_link(link)
if link_check != 1:
print(link, 'is not ok')
flash(f"{link}, 'is not ok', {link_check}", "rror")
return -1
else:
print(link, 'is ok')
#add card
#TODO ni razlike med title in vsebino urlja ??
card = Card(title=link,
@ -52,12 +61,37 @@ def commit_link(link, user_id):
share_id=0)
dbsession.add(card)
dbsession.commit()
flash(f"{link} imported successfully")
flash(f"{card.title} imported successfully")
dbsession.close()
get_engine().disolve()
return 1
@bp.route('/import_txt', methods = ('GET', 'POST'))
def import_link_from_txt():
user_id = session["user_id"]
username = session["username"]
#@TODO ta forloop bi lahko flashal postopoma
for txt_file in request.files.getlist("file"):
filename = secure_filename(txt_file.filename)
# Is there really a file?
if not filename:
flash('There is no file. Try again?')
return render_template("upload.html", username=username)
lines = txt_file.readlines()
links = [line.decode("UTF-8") for line in lines]
import_list_of_links(links, user_id)
return render_template("import_link.html", user_id=user_id, username=username)
def import_list_of_links(list_of_links, user_id):
#TODO nekak bi bilo dobro, da pokaže kateri so failali....
for link in list_of_links:
commit_link(link, user_id)
commit_link(link.strip(" ").strip("\n"), user_id)

View File

@ -3,6 +3,14 @@ import re
from flask import render_template
from urllib.parse import urlparse
def check_link(link):
parsed_url = urlparse(link)
if parsed_url.scheme and parsed_url.netloc:
return 1
else:
print("link not valid (https:// missing??)")
return -1
def check_response(link):
"""
@ -10,26 +18,32 @@ def check_response(link):
2 if there's conncetion error
3 if link is invalid (no "http" for example)
"""
parsed_url = urlparse(link)
if parsed_url.scheme and parsed_url.netloc:
try:
response = requests.head(link)
if response.status_code == 200:
return 1
else:
#TODO drugi statusi code?
return "WEIRD"
except requests.exceptions.RequestException:
print("conncetion error")
return 2
else:
print("link not valid (https:// missing??)")
return 3
#return "WEIRD", response
#TODO samo za testiranje
return f"Error: {response.status_code}"
except Exception as e:
print(e)
return f"Link error: {e}"
# kako vse možne linke embeddat?
def render_embed_link(cm_username, card, maybe_in, no_in):
url = card.item_location
response = check_response(url)
if response != 1:
render_template("embed_link/bad_link.html",
card=card,
username=cm_username,
maybe_in=maybe_in,
no_in=no_in)
if re.match(r'^https?://(www\.)?twitter\.com/.*/status/\d+$', url):
tweet_id = url.split("/")[-1]
return render_template("embed_link/twitter_embed.html",

View File

@ -3,29 +3,37 @@ from flask import (
)
from requests import get
from config import CONFIG
from create_db import Card, User, get_session
from create_db import Card, User, get_session, get_engine
bp = Blueprint('matches', __name__, url_prefix='/matches')
def get_matches(user_id):
#@TODO this is buggy
dbsession = get_session()
list_of_matches = []
#in all shared cards for the ones you voted yes
Session = get_session()
with Session() as dbsession:
all_cards = dbsession.query(Card)
all_shared_of_user_of_ir_1 = all_cards.filter(Card.share_id != "0", Card.owner_id == user_id, Card.interest_rate == "1").all()
dbsession.close()
get_engine().dispose()
if all_shared_of_user_of_ir_1 == []:
return list_of_matches
# see who else voted yes
Session = get_session()
with Session() as dbsession:
for c in all_shared_of_user_of_ir_1:
others_yes = all_cards.filter(Card.share_id == c.share_id, Card.interest_rate == "1", Card.owner_id != user_id).all()
if others_yes == []:
pass
else:
list_of_matches.append(others_yes)
dbsession.close()
get_engine().dispose()
return list_of_matches
@ -35,7 +43,6 @@ def index():
if not 'user_id' in session:
redirect(url_for('index'))
dbsession = get_session()
user_id = session["user_id"]
username = session["username"]
@ -48,7 +55,12 @@ def index():
for card in match:
user_ids.append(card.owner_id)
users = dbsession.query(User)
Session = get_session()
with Session() as dbsession:
users = dbsession.query(User).all()
dbsession.close()
get_engine().dispose()
names_by_ids = {}
emails_by_ids = {}

11
menu.py
View File

@ -1,7 +1,7 @@
from flask import (
Blueprint, redirect, render_template, request, session, url_for
)
from create_db import Card, get_session
from create_db import Card, get_session, get_engine
from sr_session import schedule_status, remaining_items, list_of_due_cards_by_ids, list_of_new_cards_by_ids, rated_today_by_staus
from settings import get_settings
from auth import login
@ -10,7 +10,7 @@ bp = Blueprint('menu', __name__, url_prefix='/menu')
@bp.route("/", methods=("GET", "POST"))
def index():
dbsession = get_session()
if 'user_id' not in session:
return login()
@ -34,11 +34,18 @@ def index():
action = request.form.get("menu", False) #internetna rešitev, nevem kako, ampak dela, tj. dobi info iz meni buttonov
if action == "new_session":
#preverimo če so sploh karte v collectionu
Session = get_session()
with Session() as dbsession:
c = dbsession.query(Card).filter(Card.owner_id == user_id).all()
if c == []:
dbsession.close()
return render_template("error/no_cards_in_collection.html", username=username)
dbsession.close()
get_engine().dispose()
return redirect(url_for("deck"))
elif action == "matches":
return redirect(url_for("matches.index"))
elif action == "upload":

View File

@ -1,4 +1,4 @@
from create_db import Card, get_session
from create_db import Card, get_session, get_engine
from config import CONFIG
import nextcloud_client
@ -17,6 +17,10 @@ for item in l:
public_share = nc.share_file_with_link("/GIA CLOUD/"+name)
public_link = public_share.get_link()+"/download/"+name
card = Card(title=name, interest_rate=-1.0, owner_id=1, item_location=public_link, last_review=None, share_id="0")
Session = get_session()
with Session() as dbsession:
dbsession.add(card)
dbsession.commit()
dbsession.close()
get_engine().dispose()

View File

@ -1,5 +1,5 @@
from flask import session, redirect, url_for,request, flash, render_template
from create_db import get_session, Deck, Card
from create_db import get_session, Deck, Card, get_engine
from share import share
"""
@ -9,13 +9,14 @@ rabi še deck funkcionalnosti, ki so bile prej v menu.py itd...
"""
def prob_session():
dbsession = get_session()
if not 'user_id' in session:
redirect(url_for('login'))
user_id = session['user_id']
username = session['username']
#pokliče na bazo, da dobi str card idjev, ga spremeni v list in srevira karte po idjih
Session = get_session()
with Session() as dbsession:
deck_query = dbsession.query(Deck).filter(Deck.owner_id == user_id)
deck_object = deck_query.filter(Deck.completed == False).first()
# @TODO: ce deck, ne obstaja, kaj naj zaj jas?
@ -29,7 +30,6 @@ def prob_session():
if not card_id:
raise Exception("card_id je nujen!")
submit_card = dbsession.query(Card).get(card_id)
# @TODO preveri, ali je card del trenutnega decka!
@ -83,6 +83,7 @@ def prob_session():
print("GET CARD PLS", show_card_id)
show_card = dbsession.query(Card).get(show_card_id)
dbsession.close()
get_engine().dispose()
if not show_card:
# @TODO how to handle missing card?

View File

@ -4,27 +4,27 @@ from requests import session
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from config import CONFIG
from create_db import Base, Card
from create_db import Base, Card, get_engine, get_session
from get_files import get_file_list
engine = create_engine(CONFIG['DB_CONNECTION'])
Base.metadata.bind = engine
DBSsession = sessionmaker(bind=engine)
session = DBSsession()
l = get_file_list()
id = 0 #TODO
for title in l:
if title[-4:] == ".pdf":
if title[-4:] != ".pdf":
continue
card = Card(
id=id,
title=title[:-4],
interest_rate=-1,
owner_id = 1
)
id = id+1
Session = get_session()
with Session() as dbsession:
session.add(card)
session.commit()
session.close()
id = id+1
get_engine().dispose()

View File

@ -1,14 +1,14 @@
from flask import flash, render_template, Blueprint, request, session
from create_db import User, get_session
from create_db import User, get_session, get_engine
import json
bp = Blueprint('settings', __name__, url_prefix='/settings')
def get_settings(user_id):
dbsession = get_session()
"""get settings from db, turns it into a dict and returns it"""
Session = get_session()
with Session() as dbsession:
user = dbsession.query(User).get(user_id)
#tu rešujejo none user bug, ki se pojavi, ko na novo reg user, ni zazznan v querryju
# zdaj imamo problem clasha med globalno in lokalno spremenljivko "dbsession"
@ -27,15 +27,16 @@ def get_settings(user_id):
settings_dict = json.loads(settings_db)
dbsession.close()
get_engine().dispose()
return settings_dict
@bp.route("/save_settings", methods=["GET", "POST"])
def save_settings():
dbsession = get_session()
"""takes a dict of settings turns it into json and updates the database with it"""
user_id = session['user_id']
username = session['username']
@ -50,7 +51,8 @@ def save_settings():
"max_due" : request.form.get('max_due', False),
"max_shared" : request.form.get('max_shared', False),
}
Session = get_session()
with Session() as dbsession:
settings_json = json.dumps(settings_dict)
user = dbsession.query(User).get(user_id)
@ -58,5 +60,6 @@ def save_settings():
dbsession.commit()
dbsession.close()
flash("settings updated")
get_engine().dispose()
return render_template("settings.html", username=username, settings=settings_dict)

View File

@ -1,18 +1,19 @@
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from config import CONFIG
from create_db import User, Card, get_session
from create_db import User, Card, get_session, get_engine
from hashlib import md5
#@TODO najbrž je treba narediti tako da org card tudi dobi share id in se ostalo, kar to obsega
def share(card, user_id):
dbsession = get_session()
#tu bi lahko naredili nek autoincrement ampak i guess da hash unique idja tudi daje unique share_id, tega potem uporabljamo, da preverimo matche
h = md5(str(card.id).encode("utf-8")).hexdigest()
card.share_id = h
Session = get_session()
with Session() as dbsession:
owner_card = dbsession.query(Card).filter(Card.id == card.id).first()
owner_card.share_id = h
dbsession.commit()
@ -26,17 +27,22 @@ def share(card, user_id):
new_card = card = Card(title=card.title, interest_rate=-1.0, owner_id=user.id, item_location=card.item_location, last_review=None, share_id=h)
dbsession.add(new_card)
dbsession.commit()
dbsession.close()
get_engine().dispose()
def get_all_shared(user_id):
"""adds all existing shared cards to this users collection"""
dbsession = get_session()
#get all cards with a shared id but make suer they are unique. add them to collection of user
#@TODO A je to resres ok?
Session = get_session()
with Session() as dbsession:
all_shared_cards = dbsession.query(Card).filter(Card.share_id != "0").distinct(Card.share_id).group_by(Card.share_id)
for c in all_shared_cards:
new_card = Card(title= c.title, interest_rate=-1.0, owner_id=user_id, item_location=c.item_location, last_review=None, share_id=c.share_id)
dbsession.add(new_card)
dbsession.commit()
dbsession.close()
get_engine().dispose()

View File

@ -3,7 +3,7 @@ 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 create_db import Card, Rating, get_session, get_engine
from settings import get_settings
from link_handler import render_embed_link
@ -12,12 +12,15 @@ from link_handler import render_embed_link
testing
"""
def autofill_ratings():
dbsession = get_session()
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
"""
@ -48,9 +51,12 @@ def get_interval(card_id):
"""
takes card_id looks at the history of rates and gives the current interval
"""
dbsession = get_session()
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
@ -60,33 +66,36 @@ def get_interval(card_id):
#to vključuje tudi new...
def is_due(card_id):
dbsession = get_session()
interval = get_interval(card_id)
if interval < 0:
return False
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()
if last_rating_date == None:
dbsession.close()
return True
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):
dbsession = get_session()
Session = get_session()
with Session() as dbsession:
rating = dbsession.query(Rating).filter(Rating.card_id == card_id).first()
dbsession.close()
if rating == None:
return True
else:
return False
get_engine().dispose()
return rating == None
def list_of_due_cards_by_ids(user_id):
"this should not include new cards"
dbsession = get_session()
Session = get_session()
with Session() as dbsession:
cards = dbsession.query(Card).filter(Card.owner_id == user_id).all()
l = []
for card in cards:
@ -95,11 +104,14 @@ def list_of_due_cards_by_ids(user_id):
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):
dbsession = get_session()
Session = get_session()
with Session() as dbsession:
cards = dbsession.query(Card).filter(Card.owner_id == user_id).all()
l = []
for card in cards:
@ -114,15 +126,16 @@ 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()
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
)
n = 0
d = 0
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)
@ -136,6 +149,8 @@ def rated_today_by_staus (card_status, user_id):
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":
@ -199,7 +214,6 @@ def remaining_by_status(user_id, status):
Engine
"""
def sr_session():
dbsession = get_session()
#check if user in session
if not 'user_id' in session:
@ -216,6 +230,8 @@ def sr_session():
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
@ -233,6 +249,7 @@ def sr_session():
dbsession.add(r)
dbsession.commit()
dbsession.close()
get_engine().dispose()
user_settings = get_settings(user_id)
max_new = int(user_settings["max_new"])
@ -262,11 +279,15 @@ def sr_session():
print("getting due")
next_card_id=get_a_card_by_status(user_id, "due")
else:
dbsession.close()
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

View File

@ -7,7 +7,7 @@ from werkzeug.utils import secure_filename
from auth import login_required
from config import CONFIG
from create_db import User, Card, get_session
from create_db import User, Card, get_session, get_engine
import nextcloud_client
import magic
@ -27,7 +27,6 @@ def index():
@bp.route('/uploader', methods = ('GET', 'POST'))
def upload_file():
dbsession = get_session()
user_id = session["user_id"]
username = session["username"]
@ -42,7 +41,13 @@ def upload_file():
return render_template("upload.html", username=username)
#prevent duplicate filenames
if dbsession.query(Card).filter(Card.title == filename).first() != None:
Session = get_session()
with Session() as dbsession:
filename_exists = dbsession.query(Card).filter(Card.title == filename).first() != None
dbsession.close()
get_engine().dispose()
if filename_exists:
flash("Filename already in database, please rename if you want to upload: " + filename, 'error')
continue
@ -62,9 +67,14 @@ def upload_file():
#add card
card = Card(title=filename, interest_rate=-1.0, owner_id=user_id, item_location=public_link, last_review=None, share_id=0)
flash(f"{filename} uploaded successfully")
Session = get_session()
with Session() as dbsession:
dbsession.add(card)
dbsession.commit()
dbsession.close()
get_engine().dispose()
else:
flash("Please insert a PDF file, support for other formats comming soon...")
#return render_template("upload.html", user_id=user_id, username=username)