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 :)

This commit is contained in:
2022-01-20 17:25:01 +11:00
parent 5461cb4036
commit 78acb9bd66
5 changed files with 132 additions and 76 deletions

4
TODO
View File

@@ -1,14 +1,12 @@
## GENERAL ## GENERAL
* for below.. make Options( request ) * 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 - 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 -- 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 - 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 * 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... don't render_template instead do a redirect to a GET of the new, or list? for del...
files.py:@app.route("/view/<id>", methods=["POST"]) [DONE] files.py:@app.route("/view/<id>", 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!
files.py:@app.route("/viewlist", 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 -- 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"]) job.py:@app.route("/jobs", methods=["GET", "POST"])

View File

@@ -20,7 +20,7 @@ import re
import json import json
import datetime import datetime
from flask_login import login_required, current_user from flask_login import login_required, current_user
from states import Options from states import States
################################################################################ ################################################################################
# Local Class imports # Local Class imports
@@ -28,7 +28,7 @@ from states import Options
from job import Job, JobExtra, Joblog, NewJob from job import Job, JobExtra, Joblog, NewJob
from path import PathType, Path from path import PathType, Path
from person import Refimg, Person, PersonRefimgLink from person import Refimg, Person, PersonRefimgLink
from settings import Settings from settings import Settings, SettingsIPath, SettingsSPath, SettingsRBPath
from shared import SymlinkName from shared import SymlinkName
from dups import Duplicates from dups import Duplicates
from face import Face, FaceFileLink, FaceRefimgLink from face import Face, FaceFileLink, FaceRefimgLink
@@ -238,8 +238,8 @@ def GetEntriesInFolderView( OPT, prefix ):
################################################################################ ################################################################################
def GetEntries( OPT ): def GetEntries( OPT ):
entries=[] entries=[]
if OPT.path_type == 'Search': if OPT.path_type == 'Search' or (OPT.path_type == 'View' and OPT.orig_ptype=='Search'):
search_term=OPT.search_term search_term=OPT.orig_search_term
if 'AI:' in search_term: if 'AI:' in search_term:
search_term = search_term.replace('AI:','') 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() 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) all_entries.append(a)
return all_entries 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): if not os.path.exists(path):
continue continue
prefix = SymlinkName(OPT.path_type,path,path+'/') prefix = SymlinkName(OPT.path_type,path,path+'/')
@@ -295,7 +313,7 @@ def clear_jm_msg(id):
@app.route("/file_list_ip", methods=["GET", "POST"]) @app.route("/file_list_ip", methods=["GET", "POST"])
@login_required @login_required
def file_list_ip(): 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 # 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': if request.method=='POST':
redirect("/file_list_ip") redirect("/file_list_ip")
@@ -308,7 +326,7 @@ def file_list_ip():
@app.route("/files_ip", methods=["GET", "POST"]) @app.route("/files_ip", methods=["GET", "POST"])
@login_required @login_required
def files_ip(): 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 # 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': if request.method=='POST':
redirect("/files_ip") redirect("/files_ip")
@@ -323,7 +341,7 @@ def files_ip():
@app.route("/files_sp", methods=["GET", "POST"]) @app.route("/files_sp", methods=["GET", "POST"])
@login_required @login_required
def files_sp(): 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 # 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': if request.method=='POST':
redirect("/files_sp") redirect("/files_sp")
@@ -339,7 +357,7 @@ def files_sp():
@app.route("/files_rbp", methods=["GET", "POST"]) @app.route("/files_rbp", methods=["GET", "POST"])
@login_required @login_required
def files_rbp(): 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 # 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': if request.method=='POST':
redirect("/files_rbp") redirect("/files_rbp")
@@ -356,7 +374,7 @@ def files_rbp():
@app.route("/search/<search_term>", methods=["GET"]) @app.route("/search/<search_term>", methods=["GET"])
@login_required @login_required
def search(search_term): def search(search_term):
OPT=Options( request ) OPT=States( request )
OPT.search_term = search_term OPT.search_term = search_term
# always show flat results for search to start with # always show flat results for search to start with
OPT.folders=False OPT.folders=False
@@ -510,7 +528,7 @@ def move_files():
@app.route("/viewlist", methods=["POST"]) @app.route("/viewlist", methods=["POST"])
@login_required @login_required
def viewlist(): 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 # 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 # to go forward how_many from offset and then use viewer.html to show that
# first obj of the new list of entries # first obj of the new list of entries
@@ -551,22 +569,19 @@ def viewlist():
@login_required @login_required
@app.route("/view/<id>", methods=["GET"]) @app.route("/view/<id>", methods=["GET"])
def view(id): def view(id):
OPT=Options( request ) OPT=States( request )
objs = {} objs = {}
print( OPT )
entries=GetEntries( OPT ) entries=GetEntries( OPT )
eids="" eids=""
for e in entries: for e in entries:
print( f"in loop deal with: {e.id}")
objs[e.id]=e objs[e.id]=e
eids += f"{e.id}," 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: if not e.file_details:
print( f"seems {e.name} is not a file? -- {e.type}" )
continue continue
# put locn data back into array format # put locn data back into array format
for face in e.file_details.faces: for face in e.file_details.faces:
face.locn = json.loads(face.locn) face.locn = json.loads(face.locn)
print("now render the viewer" )
eids=eids.rstrip(",") eids=eids.rstrip(",")
return render_template("viewer.html", current=int(id), eids=eids, objs=objs, OPT=OPT ) return render_template("viewer.html", current=int(id), eids=eids, objs=objs, OPT=OPT )
@@ -576,7 +591,9 @@ def view(id):
@app.route("/view/<id>", methods=["POST"]) @app.route("/view/<id>", methods=["POST"])
@login_required @login_required
def view_img_post(id): 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 ); return redirect( "/view/" + id );
# route called from front/end - if multiple images are being transformed, each transorm == a separate call # route called from front/end - if multiple images are being transformed, each transorm == a separate call

View File

@@ -54,8 +54,8 @@ Compress(app)
################################# Now, import separated class files ################################### ################################# Now, import separated class files ###################################
from ai import aistats from ai import aistats
from settings import Settings
from files import Entry, GetJM_Message, ClearJM_Message from files import Entry, GetJM_Message, ClearJM_Message
from settings import Settings
from person import Person from person import Person
from job import Job, GetNumActiveJobs from job import Job, GetNumActiveJobs
from user import PAUser from user import PAUser

138
states.py
View File

@@ -23,79 +23,102 @@ class PA_UserState(db.Model):
fullscreen = db.Column(db.Boolean, unique=False, nullable=False ) fullscreen = db.Column(db.Boolean, unique=False, nullable=False )
root = db.Column(db.String, unique=False, nullable=False ) root = db.Column(db.String, unique=False, nullable=False )
cwd = 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): def __repr__(self):
return f"<pa_user_dn: {self.pa_user_dn}, path_type: {self.path_type}, noo: {self.noo}, grouping: {self.grouping}, how_many: {self.how_many}, st_offset: {self.st_offset}, size: {self.size}, folders: {self.folders}, root: {self.root}, cwd: {self.cwd}>" return f"<pa_user_dn: {self.pa_user_dn}, path_type: {self.path_type}, noo: {self.noo}, grouping: {self.grouping}, how_many: {self.how_many}, st_offset: {self.st_offset}, size: {self.size}, folders: {self.folders}, root: {self.root}, cwd: {self.cwd}, view_eid: {self.view_eid}, orig_ptype: {self.orig_ptype}, orig_search_term: {self.orig_search_term}>"
################################################################################ ################################################################################
# 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 # 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. # it also handles the cwd appropriately, paths, fullscreen, search, etc.
################################################################################ ################################################################################
class Options(PA): class States(PA):
def __init__(self, request): def __init__(self, request):
self.path_type=''
self.url = request.path
# this occurs ONLY when a POST to /view/<id> occurs (at this stage orig_url will be from an import, storage, bin or search)
if 'orig_url' in request.form: 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'] url = request.form['orig_url']
# get the eid out of the url /view/<id>
self.view_eid = request.path[6:]
else: else:
url = request.path url = request.path
self.orig_url=url self.view_eid = None
if 'files_sp' in url:
self.path_type = 'Storage' if 'files_ip' in url or 'file_list_ip' in url:
self.paths = SettingsSPath() 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).first() self.orig_ptype = 'Import'
if pref:
self.folders=pref.folders
self.noo=pref.noo
else: else:
self.folders=True self.path_type = 'Import'
self.noo="A to Z" elif 'files_sp' in url:
if self.path_type == "View":
self.orig_ptype = 'Storage'
else:
self.path_type = 'Storage'
elif 'files_rbp' in url: elif 'files_rbp' in url:
self.path_type = 'Bin' if self.path_type == "View":
self.paths = [] self.orig_ptype = 'Bin'
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
else: else:
self.folders=True self.path_type = 'Bin'
self.noo="A to Z"
elif 'search' in url: elif 'search' in url:
self.path_type = 'Search' # okay if we are a search, but came from a view then get last_search_state form prefs and use it
self.paths = None 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).first() last_search_state = PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type=='Search').first()
if pref: self.orig_search_term = last_search_state.orig_search_term
self.folders=pref.folders self.orig_ptype = 'Search'
self.noo=pref.noo
else: else:
self.folders=False self.orig_search_term = url[8:]
self.noo="Oldest" 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: 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() 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: if pref:
self.folders=pref.folders
self.noo=pref.noo
self.grouping=pref.grouping self.grouping=pref.grouping
self.how_many=pref.how_many self.how_many=pref.how_many
self.offset=pref.st_offset self.offset=pref.st_offset
self.size=pref.size self.size=pref.size
self.root=pref.root self.root=pref.root
self.cwd=pref.cwd self.cwd=pref.cwd
self.orig_ptype=pref.orig_ptype
self.orig_search_term=pref.orig_search_term
else: else:
self.folders=False
self.noo="Oldest"
self.grouping="None" self.grouping="None"
self.how_many="50" self.how_many="50"
self.offset="0" self.offset="0"
self.size="128" 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 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 # 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: if 'next' in request.form:
self.offset += int(self.how_many) 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() # now save pref
if not pref: 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, # 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
st_offset=self.offset, size=self.size, folders=self.folders, root=self.root, cwd=self.cwd ) old_pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==self.path_type).delete()
else: 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,
pref.noo=self.noo 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 )
pref.grouping=self.grouping else:
pref.how_many=self.how_many pref.pa_user_dn=current_user.dn
pref.st_offset=self.offset pref.path_type=self.path_type
pref.size=self.size pref.view_eid=self.view_eid
pref.folders=self.folders pref.noo=self.noo
pref.root = self.root pref.grouping=self.grouping
pref.cwd = self.cwd 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.add(pref)
db.session.commit() db.session.commit()
return return

View File

@@ -15,7 +15,18 @@
<tbody> <tbody>
{% for st in states %} {% for st in states %}
<tr> <tr>
<td>{{st.path_type}}</td> <td>{{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 %}
</td>
<td>{{st.noo}}</td> <td>{{st.noo}}</td>
<td>{{st.how_many}}</td> <td>{{st.how_many}}</td>
<td>{{st.folders}}</td> <td>{{st.folders}}</td>