start of noo for Search, and rewrite of GetEnt* to use eval(), search and flat done, but also fixed OLD bug I just noticed where prev/next buttons would not work when sorting by "A to Z", etc. as the value of the form.input has a space in it and serializeArray() was not dealing with it properly

This commit is contained in:
2022-01-29 18:06:21 +11:00
parent 8722448f2d
commit 8e82271e2a
5 changed files with 121 additions and 83 deletions

5
TODO
View File

@@ -1,5 +1,10 @@
## GENERAL
* search allow noo
- PREFS:
- allow default and choosing search noo
- can't force fullscreen on page load, so remove it from prefs
- also need to extend the OPT.order / eval usage to the Fold views
-- also, does search of matching dirname give all entries of subdirs of subdirs, etc. (think not) -- maybe a TODO?
* [DONE] order/ find face with largest size and at least show that as unmatched
- could also try to check it vs. other faces, if it matches more than say 10? we offer it up as a required ref img, then cut that face (with margin) out and use it is a new ref image / person

184
files.py
View File

@@ -200,26 +200,17 @@ def GetEntriesInFlatView( OPT, prefix ):
entries=[]
num_entries=0
if OPT.noo == "Oldest":
entries+=Entry.query.join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).filter(Path.path_prefix==prefix).order_by(File.year,File.month,File.day,Entry.name).offset(OPT.offset).limit(OPT.how_many).all()
last_entry=Entry.query.join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).filter(Path.path_prefix==prefix).order_by(File.year.desc(),File.month.desc(),File.day.desc(),Entry.name.desc()).limit(1)
elif OPT.noo == "Newest":
entries+=Entry.query.join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).filter(Path.path_prefix==prefix).order_by(File.year.desc(),File.month.desc(),File.day.desc(),Entry.name).offset(OPT.offset).limit(OPT.how_many).all()
last_entry=Entry.query.join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).filter(Path.path_prefix==prefix).order_by(File.year,File.month,File.day,Entry.name).limit(1)
elif OPT.noo == "Z to A":
entries+=Entry.query.join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).filter(Path.path_prefix==prefix).order_by(Entry.name.desc()).offset(OPT.offset).limit(OPT.how_many).all()
last_entry=Entry.query.join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).filter(Path.path_prefix==prefix).order_by(Entry.name).limit(1)
else:
entries+=Entry.query.join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).filter(Path.path_prefix==prefix).order_by(Entry.name).offset(OPT.offset).limit(OPT.how_many).all()
last_entry=Entry.query.join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).filter(Path.path_prefix==prefix).order_by(Entry.name.desc()).limit(1)
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=Entry.query.join(File).join(EntryDirLink).join(Dir).join(PathDirLink).join(Path).filter(Path.path_prefix==prefix).count()
le=last_entry.all()
if len(le):
OPT.last_eid = le[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
return entries, num_entries
@@ -278,76 +269,111 @@ def GetEntriesInFolderView( OPT, prefix ):
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
if 'AI:' in OPT.orig_search_term:
search_term = search_term.replace('AI:','')
join=f"Entry.query.join(File).distinct().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()")
if OPT.last_eid == 0:
OPT.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
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)
# 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 ilike '%%{search_term}%%'"
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"
num_e_result = db.engine.execute( num_e_sql )
for res in num_e_result:
OPT.num_entries=res.count
last_entry_sql= f"{sel_no_order} order by {OPT.last_order_raw} limit 1"
last_entry=db.engine.execute( last_entry_sql )
# can only be 1 due to limit above
for l in last_entry:
OPT.last_eid = l.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==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
################################################################################
# /GetEntries -> helper function that Gets Entries for required files to show
# for several routes (files_ip, files_sp, files_rbp, search, viewlist)
################################################################################
def GetEntries( OPT ):
entries=[]
SetOrderStrings( OPT )
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).distinct().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()
if OPT.last_eid == 0:
OPT.num_entries = Entry.query.join(File).distinct().join(FaceFileLink).join(Face).join(FaceRefimgLink).join(Refimg).join(PersonRefimgLink).join(Person).filter(Person.tag.ilike(f"%{search_term}%")).count()
last_entry=Entry.query.join(File).distinct().join(FaceFileLink).join(Face).join(FaceRefimgLink).join(Refimg).join(PersonRefimgLink).join(Person).filter(Person.tag.ilike(f"%{search_term}%")).order_by(File.year,File.month,File.day,Entry.name.desc()).limit(1).all()
if len(last_entry):
OPT.last_eid = last_entry[0].id
else:
file_data=Entry.query.join(File).filter(Entry.name.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()
dir_data=Entry.query.join(File).join(EntryDirLink).join(Dir).filter(Dir.rel_path.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()
ai_data=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()
# 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)
# 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 ilike '%%{search_term}%%'"
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} ) "
order_desc=f"f.year desc, f.month desc, f.day desc, e.name"
order_asc=f"f.year, f.month, f.day, e.name desc"
#num_entries
num_e_sql = f"select count(1) from ( {by_fname} union {by_dirname} union {by_ai} ) as foo"
num_e_result = db.engine.execute( num_e_sql )
for res in num_e_result:
OPT.num_entries=res.count
last_entry_sql= f"{sel_no_order} order by {order_asc} limit 1"
last_entry=db.engine.execute( last_entry_sql )
# can only be 1 due to limit above
for l in last_entry:
OPT.last_eid = l.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==search_term).first()
UpdatePref( pref, OPT )
return all_entries
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

View File

@@ -1,3 +1,11 @@
// this is needed as serliazeArray doesnt handle spaces in values
// so we wrap it in this func
$.fn.serializeAndEncode = function() {
return $.map(this.serializeArray(), function(val) {
return [val.name, encodeURIComponent(val.value)].join('=');
}).join('&');
};
// grab all selected thumbnails and return a <div> containing the thumbnails
// with extra yr and date attached as attributes so we can set the default
// dir name for a move directory - not used in del, but no harm to include them

View File

@@ -172,7 +172,7 @@ class States(PA):
else:
# is a search so...
print( "For now, search defaults for noo / folders are hardcoded" )
self.noo = 'Oldest'
self.noo = 'Newest'
self.folders=False
self.cwd=self.root

View File

@@ -57,7 +57,6 @@
<span class="alert alert-primary p-2">Searched for: '{{search_term}}'</span>
</div class="col my-auto">
<script>
$('#noo').prop('disabled', 'disabled').removeClass('border-info').addClass('border-secondary').removeClass('text-info').addClass('text-secondary');
$('#folders').prop('disabled', 'disabled').removeClass('border-info').addClass('border-secondary').removeClass('text-info').addClass('text-secondary');
</script>
{% endif %}
@@ -258,11 +257,11 @@
<input type="hidden" name="cwd" id="cwd" value="{{OPT.cwd}}">
<div class="row">
<div class="col my-auto d-flex justify-content-center">
<button aria-label="prev" onClick="$.each( $('#main_form').serializeArray() , function( index, value ) { $('#nav_form').append( '<input type=hidden name=' + value['name'] +' value='+value['value'] + '>' ); })" id="prev" name="prev" class="prev sm-txt btn btn-outline-secondary">
<button aria-label="prev" onClick="$.each( $('#main_form').serializeAndEncode() , function( index, value ) { $('#nav_form').append( '<input type=hidden name=' + value['name'] +' value='+value['value'] + '>' ); })" id="prev" name="prev" class="prev sm-txt btn btn-outline-secondary">
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#prev"/></svg>
</button>
<span class="sm-txt my-auto">&nbsp;{{OPT.how_many}} files&nbsp;</span>
<button aria-label="next" onClick="$.each( $('#main_form').serializeArray() , function( index, value ) { $('#nav_form').append( '<input type=hidden name=' + value['name'] +' value='+value['value'] + '>' ); });" id="next" {{nxt_disabled}} name="next" class="next sm-txt btn btn-outline-secondary">
<button aria-label="next" onClick="$.each( $('#main_form').serializeAndEncode() , function( index, value ) { $('#nav_form').append( '<input type=hidden name=' + value['name'] +' value='+value['value'] + '>' ); });" id="next" {{nxt_disabled}} name="next" class="next sm-txt btn btn-outline-secondary">
<svg width="16" height="16" fill="currentColor"><use xlink:href="{{url_for('internal', filename='icons.svg')}}#next"/></svg>
</button>
</div>