From 78acb9bd6687ce11ce69f5405d415b0dc0297de6 Mon Sep 17 00:00:00 2001 From: Damien De Paoli Date: Thu, 20 Jan 2022 17:25:01 +1100 Subject: [PATCH] big clean up of Options -> States, total rework, now actually handles pa_user_state -> States as Import/Storage/Bin/Search or View. If Search has orig_search_term saved. If view, has orig_ptype (and orig_search_term if orig_ptype is Search) -- removed OPT.paths -> these are now worked out when we GetEntries based on pa_user_state. This now allows us to GET all URLs for image viewing allowing me to use the back-button without issues in PROD - well we will see once I commit :) --- TODO | 4 +- files.py | 51 ++++++++++------ main.py | 2 +- states.py | 138 +++++++++++++++++++++++++----------------- templates/states.html | 13 +++- 5 files changed, 132 insertions(+), 76 deletions(-) diff --git a/TODO b/TODO index 7294139..6216af0 100644 --- a/TODO +++ b/TODO @@ -1,14 +1,12 @@ ## GENERAL * for below.. make Options( request ) - - know that a view is a "path", dont rely on orig_url - remove all "Options()" that are not set by a user-choice in the F/E and just make sure new "Options" sets all defaults as needed -- viewlist can work out new view_eids server side, and pass them back as json data - can consider an optim-- new_view page makes calls to viewlist to ADD json data only, so only trigger a new "viewlist" if we dont have data for that part of the eids * going forward into search page (and probably all POSTs) does not work don't render_template instead do a redirect to a GET of the new, or list? for del... - files.py:@app.route("/view/", methods=["POST"]) - - first pass -- fails on storage in prod (view_eids was NONE, but prefs had content, odd... ALSO in dev, it did have a list but the img we were viewing was not in the list! + [DONE] files.py:@app.route("/view/", methods=["POST"]) files.py:@app.route("/viewlist", methods=["POST"]) -- this will need a total rewrite for viewer to handle fullscreen across offset/size boundaries so fix that instead job.py:@app.route("/jobs", methods=["GET", "POST"]) diff --git a/files.py b/files.py index 0bd356b..d72c7f6 100644 --- a/files.py +++ b/files.py @@ -20,7 +20,7 @@ import re import json import datetime from flask_login import login_required, current_user -from states import Options +from states import States ################################################################################ # Local Class imports @@ -28,7 +28,7 @@ from states import Options from job import Job, JobExtra, Joblog, NewJob from path import PathType, Path from person import Refimg, Person, PersonRefimgLink -from settings import Settings +from settings import Settings, SettingsIPath, SettingsSPath, SettingsRBPath from shared import SymlinkName from dups import Duplicates from face import Face, FaceFileLink, FaceRefimgLink @@ -238,8 +238,8 @@ def GetEntriesInFolderView( OPT, prefix ): ################################################################################ def GetEntries( OPT ): entries=[] - if OPT.path_type == 'Search': - search_term=OPT.search_term + if OPT.path_type == 'Search' or (OPT.path_type == 'View' and OPT.orig_ptype=='Search'): + search_term=OPT.orig_search_term if 'AI:' in search_term: search_term = search_term.replace('AI:','') all_entries = Entry.query.join(File).join(FaceFileLink).join(Face).join(FaceRefimgLink).join(Refimg).join(PersonRefimgLink).join(Person).filter(Person.tag.ilike(f"%{search_term}%")).order_by(File.year.desc(),File.month.desc(),File.day.desc(),Entry.name).offset(OPT.offset).limit(OPT.how_many).all() @@ -269,7 +269,25 @@ def GetEntries( OPT ): all_entries.append(a) return all_entries - for path in OPT.paths: + # if we are a view, then it will be of something else, e.g. a list of + # import, storage, or bin images, reset OPT.path_type so that the paths array below works + if 'View' in OPT.path_type: + eid = OPT.url[6:] + print( f"we have a view, eid={eid}" ) + #e=Entry.query.get(eid) + #OPT.path_type=e.in_dir.in_path.type.name + print( f"pt={OPT.orig_ptype}, st={OPT.orig_search_term}" ) + OPT.path_type= OPT.orig_ptype + + paths = [] + if OPT.path_type == 'Storage': + paths = SettingsSPath() + elif OPT.path_type == 'Import': + paths = SettingsIPath() + elif OPT.path_type == 'Bin': + paths.append(SettingsRBPath()) + + for path in paths: if not os.path.exists(path): continue prefix = SymlinkName(OPT.path_type,path,path+'/') @@ -295,7 +313,7 @@ def clear_jm_msg(id): @app.route("/file_list_ip", methods=["GET", "POST"]) @login_required def file_list_ip(): - OPT=Options( request ) + OPT=States( request ) # now we have reset the offset, etc. into the prefs, we can use a GET and this will be back/forward browser button safe if request.method=='POST': redirect("/file_list_ip") @@ -308,7 +326,7 @@ def file_list_ip(): @app.route("/files_ip", methods=["GET", "POST"]) @login_required def files_ip(): - OPT=Options( request ) + OPT=States( request ) # now we have reset the offset, etc. into the prefs, we can use a GET and this will be back/forward browser button safe if request.method=='POST': redirect("/files_ip") @@ -323,7 +341,7 @@ def files_ip(): @app.route("/files_sp", methods=["GET", "POST"]) @login_required def files_sp(): - OPT=Options( request ) + OPT=States( request ) # now we have reset the offset, etc. into the prefs, we can use a GET and this will be back/forward browser button safe if request.method=='POST': redirect("/files_sp") @@ -339,7 +357,7 @@ def files_sp(): @app.route("/files_rbp", methods=["GET", "POST"]) @login_required def files_rbp(): - OPT=Options( request ) + OPT=States( request ) # now we have reset the offset, etc. into the prefs, we can use a GET and this will be back/forward browser button safe if request.method=='POST': redirect("/files_rbp") @@ -356,7 +374,7 @@ def files_rbp(): @app.route("/search/", methods=["GET"]) @login_required def search(search_term): - OPT=Options( request ) + OPT=States( request ) OPT.search_term = search_term # always show flat results for search to start with OPT.folders=False @@ -510,7 +528,7 @@ def move_files(): @app.route("/viewlist", methods=["POST"]) @login_required def viewlist(): - OPT=Options( request ) + OPT=States( request ) # Get next/prev set of data - e.g. if next set, then it will use orig_url # to go forward how_many from offset and then use viewer.html to show that # first obj of the new list of entries @@ -551,22 +569,19 @@ def viewlist(): @login_required @app.route("/view/", methods=["GET"]) def view(id): - OPT=Options( request ) + OPT=States( request ) objs = {} - print( OPT ) entries=GetEntries( OPT ) eids="" for e in entries: - print( f"in loop deal with: {e.id}") objs[e.id]=e eids += f"{e.id}," + # if this is a dir, we wont view it with a click anyway, so move on... if not e.file_details: - print( f"seems {e.name} is not a file? -- {e.type}" ) continue # put locn data back into array format for face in e.file_details.faces: face.locn = json.loads(face.locn) - print("now render the viewer" ) eids=eids.rstrip(",") return render_template("viewer.html", current=int(id), eids=eids, objs=objs, OPT=OPT ) @@ -576,7 +591,9 @@ def view(id): @app.route("/view/", methods=["POST"]) @login_required def view_img_post(id): - OPT=Options( request ) + # set pa_user_states... + OPT=States( request ) + # then use back-button friendly URL (and use pa_user_states to view the right image in the right list return redirect( "/view/" + id ); # route called from front/end - if multiple images are being transformed, each transorm == a separate call diff --git a/main.py b/main.py index 43df9a2..42fb7b1 100644 --- a/main.py +++ b/main.py @@ -54,8 +54,8 @@ Compress(app) ################################# Now, import separated class files ################################### from ai import aistats -from settings import Settings from files import Entry, GetJM_Message, ClearJM_Message +from settings import Settings from person import Person from job import Job, GetNumActiveJobs from user import PAUser diff --git a/states.py b/states.py index d7cd060..f49c9a4 100644 --- a/states.py +++ b/states.py @@ -23,79 +23,102 @@ class PA_UserState(db.Model): fullscreen = db.Column(db.Boolean, unique=False, nullable=False ) root = db.Column(db.String, unique=False, nullable=False ) cwd = db.Column(db.String, unique=False, nullable=False ) + ## for now being lazy and not doing a separate table until I settle on needed fields and when + # only used if ptype == View + view_eid = db.Column(db.Integer, unique=False, nullable=False ) + orig_ptype = db.Column(db.String, unique=False, nullable=False ) + # only used if view and orig_ptype was search + orig_search_term = db.Column(db.String, unique=False, nullable=False ) def __repr__(self): - return f"" + return f"" ################################################################################ -# Options: class to store set of default values for viewing (order/size, etc.) +# States: class to store set of default values for viewing (order/size, etc.) # and if a request object (from a POST) is passed in, it returns those instead # it also handles the cwd appropriately, paths, fullscreen, search, etc. ################################################################################ -class Options(PA): +class States(PA): def __init__(self, request): + self.path_type='' + self.url = request.path + + # this occurs ONLY when a POST to /view/ occurs (at this stage orig_url will be from an import, storage, bin or search) if 'orig_url' in request.form: + self.path_type='View' + # use orig url to define defaults/look up states for 'last' import/storage/bin/search url = request.form['orig_url'] + # get the eid out of the url /view/ + self.view_eid = request.path[6:] else: url = request.path - self.orig_url=url - if 'files_sp' in url: - self.path_type = 'Storage' - self.paths = SettingsSPath() - pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type).first() - if pref: - self.folders=pref.folders - self.noo=pref.noo + self.view_eid = None + + if 'files_ip' in url or 'file_list_ip' in url: + if self.path_type == "View": + self.orig_ptype = 'Import' else: - self.folders=True - self.noo="A to Z" + self.path_type = 'Import' + elif 'files_sp' in url: + if self.path_type == "View": + self.orig_ptype = 'Storage' + else: + self.path_type = 'Storage' elif 'files_rbp' in url: - self.path_type = 'Bin' - self.paths = [] - self.paths.append(SettingsRBPath()) - pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type).first() - if pref: - self.folders=pref.folders - self.noo=pref.noo + if self.path_type == "View": + self.orig_ptype = 'Bin' else: - self.folders=True - self.noo="A to Z" + self.path_type = 'Bin' elif 'search' in url: - self.path_type = 'Search' - self.paths = None - pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type).first() - if pref: - self.folders=pref.folders - self.noo=pref.noo + # okay if we are a search, but came from a view then get last_search_state form prefs and use it + if self.path_type == "View": + last_search_state = PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type=='Search').first() + self.orig_search_term = last_search_state.orig_search_term + self.orig_ptype = 'Search' else: - self.folders=False - self.noo="Oldest" + self.orig_search_term = url[8:] + self.path_type = 'Search' + elif 'view' in url: + # use url to get eid of viewed entry + self.view_eid = self.url[6:] + self.path_type="View" + else: + print( f"ERROR: DDP messed up, failed to match URL {url} for settings this will fail, redirecting to home" ) + return + + if self.path_type == 'View': + pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type,PA_UserState.view_eid==self.view_eid).first() else: - self.path_type = 'Import' - self.paths = SettingsIPath() pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type).first() - if pref: - self.folders=pref.folders - self.noo=pref.noo - else: - self.folders=False - self.noo="Oldest" if pref: + self.folders=pref.folders + self.noo=pref.noo self.grouping=pref.grouping self.how_many=pref.how_many self.offset=pref.st_offset self.size=pref.size self.root=pref.root self.cwd=pref.cwd + self.orig_ptype=pref.orig_ptype + self.orig_search_term=pref.orig_search_term else: + self.folders=False + self.noo="Oldest" self.grouping="None" self.how_many="50" self.offset="0" self.size="128" - self.root='static/' + self.path_type + if self.path_type == "View": + self.root='static/' + self.orig_ptype + else: + self.root='static/' + self.path_type self.cwd=self.root + if not hasattr(self, 'orig_ptype'): + self.orig_ptype=None + if not hasattr(self, 'orig_search_term'): + self.orig_search_term=None # the above are defaults, if we are here, then we have current values, use them instead if they are set -- AI: searches dont set them so then we use those in the DB first @@ -135,22 +158,29 @@ class Options(PA): if 'next' in request.form: self.offset += int(self.how_many) - pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type).first() - if not pref: - pref=PA_UserState( pa_user_dn=current_user.dn, path_type=self.path_type, noo=self.noo, grouping=self.grouping, how_many=self.how_many, - st_offset=self.offset, size=self.size, folders=self.folders, root=self.root, cwd=self.cwd ) - else: - pref.noo=self.noo - pref.grouping=self.grouping - pref.how_many=self.how_many - pref.st_offset=self.offset - pref.size=self.size - pref.folders=self.folders - pref.root = self.root - pref.cwd = self.cwd + # now save pref + if not pref: + # if there is an PA_UserState( pa_user_dn=current_user.dn, # path_type=self.path_type ), then its for a different view_eid and we are viewing, delete it before we insert the new + old_pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type).delete() + pref=PA_UserState( pa_user_dn=current_user.dn, path_type=self.path_type, view_eid=self.view_eid, noo=self.noo, grouping=self.grouping, how_many=self.how_many, + st_offset=self.offset, size=self.size, folders=self.folders, root=self.root, cwd=self.cwd, orig_ptype=self.orig_ptype, orig_search_term=self.orig_search_term ) + else: + pref.pa_user_dn=current_user.dn + pref.path_type=self.path_type + pref.view_eid=self.view_eid + pref.noo=self.noo + pref.grouping=self.grouping + pref.how_many=self.how_many + pref.st_offset=self.offset + pref.size=self.size + pref.folders=self.folders + pref.root = self.root + pref.cwd = self.cwd + pref.orig_ptype = self.orig_ptype + pref.orig_search_term = self.orig_search_term - db.session.add(pref) - db.session.commit() + db.session.add(pref) + db.session.commit() return diff --git a/templates/states.html b/templates/states.html index 97b2c77..989c121 100644 --- a/templates/states.html +++ b/templates/states.html @@ -15,7 +15,18 @@ {% for st in states %} - {{st.path_type}} + {{st.path_type}} + {% if st.path_type == 'Search' %} + "{{st.orig_search_term}}" + {% endif %} + {% if st.path_type == 'View' %} + (orig: id={{st.view_eid}} in {{st.orig_ptype}}) + {% if st.orig_ptype == 'Search' %} + "{{st.orig_search_term}}" + {% endif %} + {% endif %} + + {{st.noo}} {{st.how_many}} {{st.folders}}