moved cFO() to changeOPT() into internal/js, transformed file_list_ip to work with new query_data model, made the Size buttons use modern bootstrap5 radio buttons and work again without the form for all file* routes. Removed a lot of dead code, moved code to resetNextPrev buttons to anytime we getPage, reducing code, handle setting OPT in jscript via a to_dict() for States. Overall, search and file_list_ip now work. Only main thing left is the override code
This commit is contained in:
451
files.py
451
files.py
@@ -2,7 +2,7 @@ from flask_wtf import FlaskForm
|
||||
from flask import request, render_template, redirect, send_from_directory, url_for, jsonify, make_response
|
||||
from marshmallow import Schema, fields
|
||||
from main import db, app, ma
|
||||
from sqlalchemy import Sequence, text, select
|
||||
from sqlalchemy import Sequence, text, select, union
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.orm import joinedload
|
||||
import os
|
||||
@@ -252,173 +252,6 @@ def UpdatePref( pref, OPT ):
|
||||
pref.last_used=last_used
|
||||
db.session.add(pref)
|
||||
db.session.commit()
|
||||
|
||||
################################################################################
|
||||
# GetEntriesInFlatView: func. to retrieve DB entries appropriate for flat view
|
||||
################################################################################
|
||||
def GetEntriesInFlatView( OPT, prefix ):
|
||||
entries=[]
|
||||
num_entries=0
|
||||
|
||||
join = "Entry.query.join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).filter(Path.path_prefix==prefix)"
|
||||
entries = eval( f"{join}.{OPT.order}.offset({OPT.offset}).limit({OPT.how_many}).all()" )
|
||||
|
||||
if OPT.first_eid == 0 and OPT.offset == 0 and len(entries):
|
||||
OPT.first_eid = entries[0].id
|
||||
|
||||
if OPT.last_eid==0:
|
||||
num_entries = eval( f"{join}.count()" )
|
||||
last_entry = eval( f"{join}.{OPT.last_order}.limit(1).first()" )
|
||||
if last_entry:
|
||||
OPT.last_eid = last_entry.id
|
||||
|
||||
return entries, num_entries
|
||||
|
||||
################################################################################
|
||||
# GetEntriesInFolderView: func. to retrieve DB entries appropriate for folder view
|
||||
# read inline comments to deal with variations / ordering...
|
||||
################################################################################
|
||||
def GetEntriesInFolderView( OPT, prefix ):
|
||||
entries=[]
|
||||
num_entries=0
|
||||
# okay the root cwd is fake, so treat it specially - its Dir can be found by path with dir.rel_path=''
|
||||
if os.path.dirname(OPT.cwd) == 'static':
|
||||
dir=Entry.query.join(Dir).join(PathDirLink).join(Path).filter(Dir.rel_path=='').filter(Path.path_prefix==prefix).order_by(Entry.name).first()
|
||||
# this can occur if the path in settings does not exist as it wont be in # the DB
|
||||
if not dir:
|
||||
return entries, num_entries
|
||||
# although this is 1 entry, needs to come back via all() to be iterable
|
||||
entries+= Entry.query.filter(Entry.id==dir.id).all()
|
||||
else:
|
||||
rp = OPT.cwd.replace( prefix, '' )
|
||||
# when in subdirs, replacing prefix will leave the first char as /, get rid of it
|
||||
if len(rp) and rp[0] == '/':
|
||||
rp=rp[1:]
|
||||
dir=Entry.query.join(Dir).join(PathDirLink).join(Path).filter(Dir.rel_path==rp).filter(Path.path_prefix==prefix).order_by(Entry.name).first()
|
||||
# this can occur if the path in settings does not exist as it wont be in # the DB
|
||||
if not dir:
|
||||
return entries, 0
|
||||
# dirs cant be sorted by date really, so do best I can for now
|
||||
if OPT.noo == "Z to A" or OPT.noo == "Newest":
|
||||
entries+= Entry.query.join(EntryDirLink).join(FileType).filter(EntryDirLink.dir_eid==dir.id).filter(FileType.name=='Directory').order_by(Entry.name.desc()).all()
|
||||
# just do A to Z / Oldest by default or if no valid option
|
||||
else:
|
||||
entries+= Entry.query.join(EntryDirLink).join(FileType).filter(EntryDirLink.dir_eid==dir.id).filter(FileType.name=='Directory').order_by(Entry.name).all()
|
||||
|
||||
# add any files at the current CWD (based on dir_eid in DB)
|
||||
join="Entry.query.join(File).join(EntryDirLink).filter(EntryDirLink.dir_eid==dir.id)"
|
||||
file_entries= eval( f"{join}.{OPT.order}.offset(OPT.offset).limit(OPT.how_many).all()")
|
||||
|
||||
if OPT.offset == 0 and len(file_entries):
|
||||
OPT.first_eid = file_entries[0].id
|
||||
num_entries = eval( f"{join}.count()" )
|
||||
last_entry = eval( f"{join}.{OPT.last_order}.limit(1).first()" )
|
||||
if last_entry:
|
||||
OPT.last_eid = last_entry.id
|
||||
|
||||
entries += file_entries;
|
||||
return entries, num_entries
|
||||
|
||||
|
||||
################################################################################
|
||||
# GetEntriesInSearchView: func. to retrieve DB entries appropriate for Search view
|
||||
# Defaults search is for any matching filename, contents of any matching dirname
|
||||
# and any match with AI / face for that term. Explicit, only AI match via
|
||||
# AI:<tag> syntax
|
||||
################################################################################
|
||||
def GetEntriesInSearchView( OPT ):
|
||||
search_term=OPT.orig_search_term
|
||||
# turn * wildcard into sql wildcard of %
|
||||
search_term=search_term.replace('*', '%' )
|
||||
if 'AI:' in OPT.orig_search_term:
|
||||
search_term = search_term.replace('AI:','')
|
||||
join=f"Entry.query.join(File).join(FaceFileLink).join(Face).join(FaceRefimgLink).join(Refimg).join(PersonRefimgLink).join(Person).filter(Person.tag == search_term)"
|
||||
else:
|
||||
join=f"Entry.query.join(File).join(FaceFileLink).join(Face).join(FaceRefimgLink).join(Refimg).join(PersonRefimgLink).join(Person).filter(Person.tag.ilike('%{search_term}%'))"
|
||||
if 'AI:' in OPT.orig_search_term:
|
||||
all_entries = eval( f"{join}.{OPT.order}.offset(OPT.offset).limit(OPT.how_many).all()")
|
||||
else:
|
||||
file_data=eval( f"Entry.query.join(File).filter(Entry.name.ilike('%{search_term}%')).{OPT.order}.offset({OPT.offset}).limit({OPT.how_many}).all()" )
|
||||
dir_data =eval( f"Entry.query.join(File).join(EntryDirLink).join(Dir).filter(Dir.rel_path.ilike('%{search_term}%')).{OPT.order}.offset({OPT.offset}).limit({OPT.how_many}).all()" )
|
||||
ai_data =eval( f"{join}.{OPT.order}.offset({OPT.offset}).limit({OPT.how_many}).all()")
|
||||
|
||||
# remove any duplicates from combined data
|
||||
all_entries = []
|
||||
for f in file_data:
|
||||
all_entries.append(f)
|
||||
for d in dir_data:
|
||||
add_it=1
|
||||
for f in file_data:
|
||||
if d.name == f.name:
|
||||
add_it=0
|
||||
break
|
||||
if add_it:
|
||||
all_entries.append(d)
|
||||
for a in ai_data:
|
||||
add_it=1
|
||||
for f in file_data:
|
||||
if a.name == f.name:
|
||||
add_it=0
|
||||
break
|
||||
if add_it:
|
||||
all_entries.append(a)
|
||||
|
||||
# nothing found, just return now
|
||||
if len(all_entries) == 0:
|
||||
OPT.num_entries = 0
|
||||
return []
|
||||
|
||||
# for all searches first_entry is worked out when first_eid not set yet & offset is 0 and we have some entries
|
||||
if OPT.first_eid == 0 and OPT.offset == 0 and len(all_entries):
|
||||
OPT.first_eid = all_entries[0].id
|
||||
if OPT.last_eid == 0:
|
||||
by_fname= f"select e.id from entry e where e.name ilike '%%{search_term}%%'"
|
||||
by_dirname=f"select e.id from entry e, entry_dir_link edl where edl.entry_id = e.id and edl.dir_eid in ( select d.eid from dir d where d.rel_path ilike '%%{search_term}%%' )"
|
||||
by_ai =f"select e.id from entry e, face_file_link ffl, face_refimg_link frl, person_refimg_link prl, person p where e.id = ffl.file_eid and frl.face_id = ffl.face_id and frl.refimg_id = prl.refimg_id and prl.person_id = p.id and p.tag = '{search_term}'"
|
||||
|
||||
if 'AI:' in OPT.orig_search_term:
|
||||
sel_no_order=f"select e.*, f.* from entry e, file f where e.id=f.eid and e.id in ( {by_ai} ) "
|
||||
else:
|
||||
sel_no_order=f"select e.*, f.* from entry e, file f where e.id=f.eid and e.id in ( {by_fname} union {by_dirname} union {by_ai} ) "
|
||||
|
||||
#num_entries
|
||||
num_e_sql = f"select count(1) from ( {by_fname} union {by_dirname} union {by_ai} ) as foo"
|
||||
with db.engine.connect() as conn:
|
||||
OPT.num_entries = conn.execute( text( num_e_sql ) ).first().count
|
||||
|
||||
if OPT.num_entries == 0:
|
||||
return []
|
||||
|
||||
last_entry_sql= f"{sel_no_order} order by {OPT.last_order_raw} limit 1"
|
||||
with db.engine.connect() as conn:
|
||||
OPT.last_eid = conn.execute( text( last_entry_sql ) ).first().id
|
||||
# store first/last eid into prefs
|
||||
pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==OPT.path_type,PA_UserState.orig_ptype==OPT.orig_ptype,PA_UserState.orig_search_term==OPT.orig_search_term).first()
|
||||
UpdatePref( pref, OPT )
|
||||
return all_entries
|
||||
|
||||
################################################################################
|
||||
# set up "order strings" to use in ORM and raw queries as needed for
|
||||
# GetEntries*Search*, GetEntries*Flat*, GetEntries*Fold*
|
||||
################################################################################
|
||||
def SetOrderStrings( OPT ):
|
||||
if OPT.noo == "Newest":
|
||||
OPT.order="order_by(File.year.desc(),File.month.desc(),File.day.desc(),Entry.name.desc())"
|
||||
OPT.last_order="order_by(File.year,File.month,File.day,Entry.name)"
|
||||
OPT.last_order_raw=f"f.year, f.month, f.day, e.name"
|
||||
elif OPT.noo == "Oldest":
|
||||
OPT.order="order_by(File.year,File.month,File.day,Entry.name)"
|
||||
OPT.last_order="order_by(File.year.desc(),File.month.desc(),File.day.desc(),Entry.name.desc())"
|
||||
OPT.last_order_raw=f"f.year desc, f.month desc, f.day desc, e.name desc"
|
||||
elif OPT.noo == "Z to A":
|
||||
OPT.order="order_by(Entry.name.desc())"
|
||||
OPT.last_order="order_by(Entry.name)"
|
||||
OPT.last_order_raw=f"e.name"
|
||||
else:
|
||||
# A to Z
|
||||
OPT.order="order_by(Entry.name)"
|
||||
OPT.last_order="order_by(Entry.name.desc())"
|
||||
OPT.last_order_raw=f"e.name desc"
|
||||
return
|
||||
|
||||
################################################################################
|
||||
@@ -431,9 +264,6 @@ def process_ids():
|
||||
data = request.get_json() # Parse JSON body
|
||||
ids = data.get('ids', []) # Extract list of ids
|
||||
|
||||
# DDP: debate here, do I get query_id, do I validate whether we are asking
|
||||
# for ids not in the query? OR, dont even make/store/have query?
|
||||
|
||||
# Query DB for matching entries
|
||||
stmt = (
|
||||
select(Entry)
|
||||
@@ -473,23 +303,63 @@ def get_dir_entries():
|
||||
|
||||
# get content of dir_id
|
||||
stmt=( select(Entry.id).join(EntryDirLink).filter(EntryDirLink.dir_eid==dir_id) )
|
||||
stmt=stmt.order_by(*order_map.get(OPT.noo) )
|
||||
ids=db.session.execute(stmt).scalars().all()
|
||||
entries_schema = EntrySchema(many=True)
|
||||
entries = Entry.query.filter(Entry.id.in_(ids)).all()
|
||||
return jsonify(entries_schema.dump(entries))
|
||||
|
||||
|
||||
################################################################################
|
||||
# Call this ONCE on first menu choice of View files, or search box submission
|
||||
# create the list of entry ids that matcht the required viewing/list
|
||||
# Get all relevant Entry.ids based on search_term passed in and OPT visuals
|
||||
################################################################################
|
||||
def GetSearchQueryData(OPT):
|
||||
query_data={}
|
||||
query_data['entry_list']=None
|
||||
query_data['root_eid']=0
|
||||
|
||||
search_term = OPT.search_term
|
||||
# turn * wildcard into sql wildcard of %
|
||||
search_term = search_term.replace('*', '%')
|
||||
if 'AI:' in search_term:
|
||||
search_term = search_term.replace('AI:', '')
|
||||
|
||||
# AI searches are for specific ppl/joins in the DB AND we do them for ALL types of searches, define this once
|
||||
ai_query = (
|
||||
select(Entry.id)
|
||||
.join(File).join(FaceFileLink).join(Face).join(FaceRefimgLink).join(Refimg).join(PersonRefimgLink).join(Person)
|
||||
.where(Person.tag == search_term)
|
||||
.order_by(*order_map.get(OPT.noo) )
|
||||
)
|
||||
|
||||
if 'AI:' in search_term:
|
||||
all_entries = db.session.execute(ai_query).scalars().all()
|
||||
else:
|
||||
# match name of File
|
||||
file_query = select(Entry.id).join(File).where(Entry.name.ilike(f'%{search_term}%')).order_by(*order_map.get(OPT.noo))
|
||||
# match name of Dir
|
||||
dir_query = select(Entry.id).join(File).join(EntryDirLink).join(Dir).where(Dir.rel_path.ilike(f'%{search_term}%')).order_by(*order_map.get(OPT.noo))
|
||||
|
||||
# Combine ai, file & dir matches with union() to dedup and then order them
|
||||
combined_query = union( file_query, dir_query, ai_query )
|
||||
all_entries = db.session.execute(combined_query).scalars().all()
|
||||
|
||||
query_data['entry_list']=all_entries
|
||||
return query_data
|
||||
|
||||
|
||||
#################################################################################
|
||||
# Get all relevant Entry.ids based on files_ip/files_sp/files_rbp and OPT visuals
|
||||
#################################################################################
|
||||
def GetQueryData( OPT ):
|
||||
query_data={}
|
||||
query_data['entry_list']=None
|
||||
|
||||
# always get the top of the (OPT.prefix) Path's eid and keep it for OPT.folders toggling/use
|
||||
dir_stmt=( select(Entry.id).join(Dir).join(PathDirLink).join(Path).
|
||||
filter(Dir.rel_path == '').filter(Path.path_prefix==OPT.prefix) )
|
||||
dir_stmt=(
|
||||
select(Entry.id)
|
||||
.join(Dir).join(PathDirLink).join(Path)
|
||||
.where(Dir.rel_path == '').where(Path.path_prefix==OPT.prefix)
|
||||
)
|
||||
# this should return the 1 Dir (that we want to see the content of) - and with only 1, no need to worry about order
|
||||
dir_arr=db.session.execute(dir_stmt).scalars().all()
|
||||
dir_id=dir_arr[0]
|
||||
@@ -501,75 +371,28 @@ def GetQueryData( OPT ):
|
||||
stmt=( select(Entry.id).join(EntryDirLink).filter(EntryDirLink.dir_eid==dir_id) )
|
||||
else:
|
||||
# get every File that is in the OPT.prefix Path
|
||||
stmt=( select(Entry.id).join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).
|
||||
filter(Path.path_prefix == OPT.prefix) )
|
||||
stmt=(
|
||||
select(Entry.id)
|
||||
.join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path)
|
||||
.where(Path.path_prefix == OPT.prefix)
|
||||
)
|
||||
|
||||
stmt=stmt.order_by(*order_map.get(OPT.noo) )
|
||||
query_data['entry_list']=db.session.execute(stmt).scalars().all()
|
||||
|
||||
return query_data
|
||||
|
||||
################################################################################
|
||||
# /GetEntries -> helper function that Gets Entries for required files to show
|
||||
# for several routes (ifles_ip, files_sp, files_rbp, search, view_list)
|
||||
################################################################################
|
||||
def GetEntries( OPT ):
|
||||
entries=[]
|
||||
|
||||
SetOrderStrings( OPT )
|
||||
if OPT.path_type == 'Search' or (OPT.path_type == 'View' and OPT.orig_ptype=='Search'):
|
||||
return GetEntriesInSearchView( OPT )
|
||||
|
||||
# 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:]
|
||||
OPT.path_type= OPT.orig_ptype
|
||||
|
||||
paths = []
|
||||
if OPT.path_type == 'Storage':
|
||||
path = SettingsSPath()
|
||||
elif OPT.path_type == 'Import':
|
||||
path = SettingsIPath()
|
||||
elif OPT.path_type == 'Bin':
|
||||
path = SettingsRBPath()
|
||||
|
||||
num_entries=0
|
||||
path_cnt=1
|
||||
|
||||
# if we have not set last_eid yet, then we need to 'reset' it during the
|
||||
# path loop below (if we have more than one dir in (say) Import path)
|
||||
if OPT.last_eid == 0 or OPT.folders:
|
||||
update_last_eid = True
|
||||
else:
|
||||
update_last_eid = False
|
||||
prefix = SymlinkName(OPT.path_type,path,path+'/')
|
||||
if OPT.folders:
|
||||
tmp_ents, tmp_num_ents = GetEntriesInFolderView( OPT, prefix )
|
||||
else:
|
||||
tmp_ents, tmp_num_ents = GetEntriesInFlatView( OPT, prefix )
|
||||
entries += tmp_ents
|
||||
num_entries += tmp_num_ents
|
||||
|
||||
if update_last_eid:
|
||||
# find pref... via path_type if we are here
|
||||
OPT.num_entries=num_entries
|
||||
pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.path_type==OPT.path_type).first()
|
||||
UpdatePref( pref, OPT )
|
||||
|
||||
return entries
|
||||
|
||||
################################################################################
|
||||
# /change_file_opts -> allow sort order, how_many per page, etc. to change, and
|
||||
# then send back the new query_data to update entryList
|
||||
################################################################################
|
||||
@app.route("/change_file_opts", methods=["POST"])
|
||||
@login_required
|
||||
def change_file_opts2():
|
||||
def change_file_opts():
|
||||
data = request.get_json() # Parse JSON body
|
||||
# allow dot-notation for OPT
|
||||
OPT = SimpleNamespace(**data)
|
||||
if OPT.folders == 'True':
|
||||
if hasattr(OPT, 'folders') and OPT.folders == 'True':
|
||||
OPT.folders=True
|
||||
else:
|
||||
OPT.folders=False
|
||||
@@ -581,26 +404,20 @@ def change_file_opts2():
|
||||
################################################################################
|
||||
# /file_list -> show detailed file list of files from import_path(s)
|
||||
################################################################################
|
||||
@app.route("/file_list_ip", methods=["GET", "POST"])
|
||||
@app.route("/file_list_ip", methods=["GET"])
|
||||
@login_required
|
||||
def file_list_ip():
|
||||
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")
|
||||
entries=GetEntries( OPT )
|
||||
return render_template("file_list.html", page_title='View File Details (Import Path)', entry_data=entries, OPT=OPT )
|
||||
query_data = GetQueryData( OPT )
|
||||
return render_template("file_list.html", page_title='View File Details (Import Path)', query_data=query_data, OPT=OPT )
|
||||
|
||||
################################################################################
|
||||
# /files -> show thumbnail view of files from import_path(s)
|
||||
################################################################################
|
||||
@app.route("/files_ip", methods=["GET", "POST"])
|
||||
@app.route("/files_ip", methods=["GET"])
|
||||
@login_required
|
||||
def files_ip():
|
||||
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")
|
||||
people = Person.query.all()
|
||||
move_paths = MovePathDetails()
|
||||
query_data = GetQueryData( OPT )
|
||||
@@ -609,13 +426,10 @@ def files_ip():
|
||||
################################################################################
|
||||
# /files -> show thumbnail view of files from storage_path
|
||||
################################################################################
|
||||
@app.route("/files_sp", methods=["GET", "POST"])
|
||||
@app.route("/files_sp", methods=["GET"])
|
||||
@login_required
|
||||
def files_sp():
|
||||
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")
|
||||
people = Person.query.all()
|
||||
move_paths = MovePathDetails()
|
||||
query_data = GetQueryData( OPT )
|
||||
@@ -625,13 +439,10 @@ def files_sp():
|
||||
################################################################################
|
||||
# /files -> show thumbnail view of files from recycle_bin_path
|
||||
################################################################################
|
||||
@app.route("/files_rbp", methods=["GET", "POST"])
|
||||
@app.route("/files_rbp", methods=["GET"])
|
||||
@login_required
|
||||
def files_rbp():
|
||||
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")
|
||||
people = Person.query.all()
|
||||
move_paths = MovePathDetails()
|
||||
query_data = GetQueryData( OPT )
|
||||
@@ -645,19 +456,13 @@ def files_rbp():
|
||||
@app.route("/search/<search_term>", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def search(search_term):
|
||||
# print( f"req={request}" )
|
||||
OPT=States( request )
|
||||
# print( f"OPT={OPT}" )
|
||||
|
||||
# if we posted to get here, its a change in State, so save it to pa_user_state, and go back to the GET version or URL
|
||||
if request.method=="POST":
|
||||
redirect("/search/"+search_term)
|
||||
OPT.search_term = search_term
|
||||
# always show flat results for search to start with
|
||||
OPT.folders=False
|
||||
entries=GetEntries( OPT )
|
||||
OPT.folders = False
|
||||
|
||||
query_data=GetSearchQueryData( OPT )
|
||||
move_paths = MovePathDetails()
|
||||
return render_template("files.html", page_title='View Files', search_term=search_term, entry_data=entries, OPT=OPT, move_paths=move_paths )
|
||||
return render_template("files.html", page_title='View Files', search_term=search_term, query_data=query_data, OPT=OPT, move_paths=move_paths )
|
||||
|
||||
################################################################################
|
||||
# /files/scan_ip -> allows us to force a check for new files
|
||||
@@ -786,80 +591,8 @@ def move_files():
|
||||
return make_response( jsonify( job_id=job.id ) )
|
||||
|
||||
@login_required
|
||||
@app.route("/view_list", methods=["POST"])
|
||||
def view_list():
|
||||
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
|
||||
entries=GetEntries( OPT )
|
||||
# this occurs when we went from the last image on a page (with how_many on
|
||||
# it) and it just happened to also be the last in the DB...
|
||||
if not entries:
|
||||
SetFELog( message="DDP: DONT think this can happen anymore", level="danger", job=None, persistent=True, cant_close=True )
|
||||
|
||||
# undo the skip by how_many and getentries again
|
||||
OPT.offset -= int(OPT.how_many)
|
||||
entries=GetEntries( OPT )
|
||||
# now flag we are at the last in db, to reset current below
|
||||
objs = {}
|
||||
eids=""
|
||||
resp={}
|
||||
resp['objs']={}
|
||||
for e in entries:
|
||||
if not e.file_details:
|
||||
continue
|
||||
eids=eids+f"{e.id},"
|
||||
resp['objs'][e.id]={}
|
||||
resp['objs'][e.id]['url'] = e.FullPathOnFS()
|
||||
resp['objs'][e.id]['name'] = e.name
|
||||
resp['objs'][e.id]['type'] = e.type.name
|
||||
if e.file_details.faces:
|
||||
# model is used for whole file, so set it at that level (based on first face)
|
||||
resp['objs'][e.id]['face_model'] = e.file_details.faces[0].facefile_lnk.model_used
|
||||
resp['objs'][e.id]['faces'] = []
|
||||
|
||||
# put face data back into array format (for js processing)
|
||||
for face in e.file_details.faces:
|
||||
fd= {}
|
||||
fd['x'] = face.face_left
|
||||
fd['y'] = face.face_top
|
||||
fd['w'] = face.w
|
||||
fd['h'] = face.h
|
||||
if face.refimg:
|
||||
fd['pid'] = face.refimg.person.id
|
||||
fd['who'] = face.refimg.person.tag
|
||||
fd['distance'] = round(face.refimg_lnk.face_distance,2)
|
||||
resp['objs'][e.id]['faces'].append(fd)
|
||||
|
||||
eids=eids.rstrip(",")
|
||||
lst = eids.split(',')
|
||||
if 'next' in request.form:
|
||||
OPT.current = int(lst[0])
|
||||
if 'prev' in request.form:
|
||||
OPT.current = int(lst[-1])
|
||||
|
||||
resp['current']=OPT.current
|
||||
# OPT.first_eid can still be 0 IF we have gone past the first page, I could
|
||||
# better set this in states rather than kludge this if... think about it
|
||||
if OPT.first_eid>0:
|
||||
resp['first_eid']=OPT.first_eid
|
||||
resp['last_eid']=OPT.last_eid
|
||||
resp['eids']=eids
|
||||
resp['offset']=OPT.offset
|
||||
# print( f"BUG-DEBUG: /view_list route #1 - OPT={OPT}, eids={eids} ")
|
||||
# save pref to keep the new current value, first/last
|
||||
pref=PA_UserState.query.filter(PA_UserState.pa_user_dn==current_user.dn,PA_UserState.orig_ptype==OPT.orig_ptype,PA_UserState.view_eid==OPT.view_eid).first()
|
||||
# print( f"BUG-DEBUG: /view_list route #2 - OPT={OPT}, eids={eids} ")
|
||||
UpdatePref( pref, OPT )
|
||||
# print( f"BUG-DEBUG: /view_list route #3 - OPT={OPT}, eids={eids} ")
|
||||
|
||||
return make_response( resp )
|
||||
|
||||
|
||||
@login_required
|
||||
@app.route("/newview/", methods=["POST"])
|
||||
def newview():
|
||||
@app.route("/view/", methods=["POST"])
|
||||
def view():
|
||||
data = request.get_json() # Parse JSON body
|
||||
eid = data.get('eid', 0) # Extract list of ids
|
||||
|
||||
@@ -882,22 +615,9 @@ def newview():
|
||||
data=db.session.execute(stmt).unique().scalars().all()
|
||||
return jsonify(entries_schema.dump(data))
|
||||
|
||||
################################################################################
|
||||
# /view/id -> grabs data from DB and views it (GET)
|
||||
################################################################################
|
||||
@login_required
|
||||
@app.route("/view/<id>", methods=["GET"])
|
||||
def view(id):
|
||||
OPT=States( request )
|
||||
objs = {}
|
||||
entries=GetEntries( OPT )
|
||||
eids=""
|
||||
for e in entries:
|
||||
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:
|
||||
continue
|
||||
|
||||
####
|
||||
"""
|
||||
# process any overrides
|
||||
for face in e.file_details.faces:
|
||||
# now get any relevant override and store it in objs...
|
||||
@@ -909,20 +629,6 @@ def view(id):
|
||||
mo.type = FaceOverrideType.query.filter( FaceOverrideType.name== 'Manual match to existing person' ).first()
|
||||
face.manual_override=mo
|
||||
|
||||
eids=eids.rstrip(",")
|
||||
# jic, sometimes we trip this, and rather than show broken pages / destroy
|
||||
if id not in eids:
|
||||
# SetFELog( message=f"ERROR: viewing an id, but its not in eids OPT={OPT}, id={id}, eids={eids}", level="danger", persistent=True, cant_close=False)
|
||||
# msg="Sorry, viewing data is confused, cannot view this image now"
|
||||
# if os.environ['ENV'] == "production":
|
||||
# msg += "Clearing out all states. This means browser back buttons will not work, please start a new tab and try again"
|
||||
# PA_UserState.query.delete()
|
||||
# db.session.commit()
|
||||
# SetFELog( msg, "warning", persistent=True, cant_close=False )
|
||||
# return redirect("/")
|
||||
print( f"id={id}, eids={eids}" )
|
||||
return "200"
|
||||
else:
|
||||
NMO_data = FaceOverrideType.query.all()
|
||||
setting = Settings.query.first()
|
||||
imp_path = setting.import_path
|
||||
@@ -930,18 +636,7 @@ def view(id):
|
||||
bin_path = setting.recycle_bin_path
|
||||
# print( f"BUG-DEBUG: /view/id GET route - OPT={OPT}, eids={eids}, current={int(id)} ")
|
||||
return render_template("viewer.html", current=int(id), eids=eids, objs=objs, OPT=OPT, NMO_data=NMO_data, imp_path=imp_path, st_path=st_path, bin_path=bin_path )
|
||||
|
||||
##################################################################################
|
||||
# /view/id -> grabs data from DB and views it (POST -> set state, redirect to GET)
|
||||
##################################################################################
|
||||
@app.route("/view/<id>", methods=["POST"])
|
||||
@login_required
|
||||
def view_img_post(id):
|
||||
# set pa_user_states...
|
||||
OPT=States( request )
|
||||
# print( f"BUG-DEBUG: /view/id POST route - OPT={OPT}, id={id} ")
|
||||
# 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
|
||||
# to this route (and therefore a separate transorm job. Each reponse allows the f/e to check the
|
||||
@@ -1006,14 +701,6 @@ def _jinja2_filter_toplevelfolderof(path, cwd):
|
||||
else:
|
||||
return False
|
||||
|
||||
###############################################################################
|
||||
# This func creates a new filter in jinja2 to test to hand back the parent path
|
||||
# from a given path
|
||||
################################################################################
|
||||
@app.template_filter('ParentPath')
|
||||
def _jinja2_filter_parentpath(path):
|
||||
return os.path.dirname(path)
|
||||
|
||||
###############################################################################
|
||||
# route to allow the Move Dialog Box to pass a date (YYYYMMDD) and returns a
|
||||
# json list of existing dir names that could be near it in time. Starting
|
||||
|
||||
Reference in New Issue
Block a user