diff --git a/TODO b/TODO index 9550eeb..5d376de 100644 --- a/TODO +++ b/TODO @@ -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 diff --git a/files.py b/files.py index 3f7e63a..6710733 100644 --- a/files.py +++ b/files.py @@ -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: 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 diff --git a/internal/js/files_support.js b/internal/js/files_support.js index e41639a..affe785 100644 --- a/internal/js/files_support.js +++ b/internal/js/files_support.js @@ -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
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 diff --git a/states.py b/states.py index bec0f8f..d289c73 100644 --- a/states.py +++ b/states.py @@ -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 diff --git a/templates/files.html b/templates/files.html index 058cd05..5995298 100644 --- a/templates/files.html +++ b/templates/files.html @@ -57,7 +57,6 @@ Searched for: '{{search_term}}'
{% endif %} @@ -258,11 +257,11 @@
-  {{OPT.how_many}} files  -