added viewing recycle bin via folders, added comments, cleaned up TODO to note this is done

This commit is contained in:
2021-05-26 18:32:52 +10:00
parent 8dc98dd368
commit 9b926938e4
4 changed files with 75 additions and 28 deletions

20
TODO
View File

@@ -1,20 +1,13 @@
## GENERAL
* on start up, should validate the import/storage/recycle bin paths exist and spit an error if they dont
* dont process duplicates from Bin
* never process duplicates from Bin (allow them to be created on startup so they can be viewed?)
* issue where someone could call IP .../Imp/photos and SP .../Sto/photos and then static/photos is ambiguous:
-- DONE: make path prefix by static/<ptype.name>/ so that files are in: static/<ptype.name>/in_path.pp/dir.rel_path/
-- then deleting below would just path_prefix from static/storage to .pa_bin/storage, etc.
-- need to create the subdir if it does not exist in recycle_bin_path
*** THINK: should bin be a normal path/dir name, and in static too -- I think it will be easier in hindsight -- so need to change dst_dir when os.replace is used
-- need to be able to view recycle bin (should be simple when we have path_types) &&& should able to consolidate the files_ip/files_sp/files_rb? route handling functions
-- could also allow undelete per file / show content as another Files->View and more like storage (i.e. show folders)
* storage_path viewing needs to be by folder / not a big grab bag of files (by default - DONE)
-- BUG: issue with view by Day, etc. we print out day even if the Entry is not in the cwd
-- TODO: Need to toggle the view if I want, and when viewing storage area, change single-click to be view file again, and right-click to be my context menu
* * import_path can be folder view and is DONE but needs toggle as above
* need a way for search results to show we found something in import_path or storage_path:
- now we can use the in_path, then have a series of icons, e.g. disk for storage, ? for import, and bin for recycling (before the blue path)--maybe even show different colours, e.g. info for import, primary for storage and danger for bin?
- now we can use the in_path, then have a series of icons, e.g. disk for storage, ? for import, and bin for recycling
-- only show these on the thumbs *IF* we search (where it may not be obvious where it came from)
* handle thumbs:
- need to ignore *thumb* -- but consider how we do this and don't screw up 'dir/job counts'
and potentially other stuff like .pa_bin if its in storage/import folder?
@@ -22,6 +15,9 @@
* comment your code
* more OO goodness :)
## MAYBE?
* can we consolidate the files_ip/files_sp/files_rbp route handling functions???
* could also allow undelete per file / show content as another Files->View and more like storage (i.e. show folders)
## DB
Need to think about...
@@ -64,9 +60,6 @@
need to copy into here the jquery/fa files so we don't need internet to function
- for that matter run lightspeed against all this
file view should have show folders / flat as a choosable somehow
sorter...
need some way to multiselect images [DONE]
and then get them into a new "folder"
@@ -89,4 +82,3 @@
* exif processing?
* location stuff - test a new photo from my camera out
-- image is in dir, need to look at exifread output

View File

@@ -134,8 +134,10 @@ def ViewingOptions( request ):
size=128
if 'files_sp' in request.path:
folders=True
# this is the default as 'Storage' is the path_type in the DB
cwd='static/Storage'
elif 'files_rbp' in request.path:
folders=True
cwd='static/Bin'
else:
folders=False
cwd=None
@@ -181,7 +183,7 @@ def files_ip():
noo, grouping, how_many, offset, size, folders, cwd, root = ViewingOptions( request )
entries=[]
# per import path, add entries to view
# per import path, add entries to view
settings=Settings.query.first()
paths = settings.import_path.split("#")
for path in paths:
@@ -206,7 +208,7 @@ def files_sp():
print( f"cwd={cwd}" )
# per storage path, add entries to view
# per storage path, add entries to view
settings=Settings.query.first()
paths = settings.storage_path.split("#")
for path in paths:
@@ -220,6 +222,33 @@ def files_sp():
entries+=Entry.query.join(Dir).join(EntryDirLink).join(PathDirLink).join(Path).filter(Path.path_prefix==prefix).order_by(Entry.name).offset(offset).limit(how_many).all()
return render_template("files.html", page_title='View Files (Storage Path)', entry_data=entries, noo=noo, grouping=grouping, how_many=how_many, offset=offset, size=size, folders=folders, cwd=cwd, root=root )
################################################################################
# /files -> show thumbnail view of files from storage_path
################################################################################
@app.route("/files_rbp", methods=["GET", "POST"])
def files_rbp():
noo, grouping, how_many, offset, size, folders, cwd, root = ViewingOptions( request )
entries=[]
print( f"cwd={cwd}" )
# per recyle bin path, add entries to view
settings=Settings.query.first()
paths = settings.recycle_bin_path.split("#")
for path in paths:
prefix = SymlinkName("Bin",path,path+'/')
if 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(offset).limit(how_many).all()
else:
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(offset).limit(how_many).all()
entries+=Entry.query.join(Dir).join(EntryDirLink).join(PathDirLink).join(Path).filter(Path.path_prefix==prefix).order_by(Entry.name).offset(offset).limit(how_many).all()
print( f"dirs={Entry.query.join(Dir).join(EntryDirLink).join(PathDirLink).join(Path).filter(Path.path_prefix==prefix).order_by(Entry.name).offset(offset).limit(how_many).all()}" )
return render_template("files.html", page_title='View Files (Bin Path)', entry_data=entries, noo=noo, grouping=grouping, how_many=how_many, offset=offset, size=size, folders=folders, cwd=cwd, root=root )
################################################################################
# /search -> show thumbnail view of files from import_path(s)
################################################################################

View File

@@ -495,6 +495,19 @@ def CreateSymlink(job,ptype,path):
os.symlink(path, symlink)
return symlink
################################################################################################################################################################
#
# Key function that runs as part of (usually) an import job. The name of the directory (dirname) is checked to see
# if it already is in the database (inside of in_dir in in_path). If it is,
# just return the db entry. If not, then we create a new row in Dir, that has name of dirname, has a parent directory
# of in_dir (DB object), has the rel_path set to the relative fs path from the actual fs path to this entry (including the dirname)
# and the in_path set to the overarching path (one of an Import, Storage or Recycle_bin path in the DB)
#
# e.g. path on FS: /home/ddp/src/photoassistant/images_to_process/ ... ends in DB as path_prefix="static/Import/images_to_process"
# and we have a dir in /home/ddp/src/photoassistant/images_to_process/0000/subtest, then we call:
# AddDir( job, dirname='subtest', in_dir=Dir object for '0000', rel_path='0000/subtest', in_path=Path object for 'static/Import/images_to_process' )
#
################################################################################################################################################################
def AddDir(job, dirname, in_dir, rel_path, in_path ):
dir=session.query(Dir).join(PathDirLink).join(Path).filter(Path.id==in_path.id).filter(Dir.rel_path==rel_path).first()
if dir:
@@ -573,16 +586,28 @@ def MoveFileToRecycleBin(job,del_me):
os.replace( src, dst )
except Exception as e:
print( f"Failed to remove file from filesystem - which={src}, err: {e}")
bin=session.query(Path).join(PathType).filter(PathType.name=='Bin').first()
print("bin={bin}")
print("del_me={del_me}")
bin_path=session.query(Path).join(PathType).filter(PathType.name=='Bin').first()
print( f"bin={bin}")
print( f"del_me={del_me}")
new_rel_path=del_me.in_dir.in_path.path_prefix.replace('static/','')
# if there is a relative path on this dir, add it to the new_rel_path as there is only ever 1 Bin path
if len(del_me.in_dir.rel_path):
new_rel_path += '/' + del_me.in_dir.rel_path
print("new_rel_path={new_rel_path}")
new_dir = AddDir(job, new_rel_path, None, new_rel_path, bin )
print( "new_dir={new_dir}" )
print( f"new_rel_path={new_rel_path}" )
parent_dir=session.query(Dir).join(PathDirLink).filter(PathDirLink.path_id==bin_path.id).first()
print( f"parent_dir for path={parent_dir}" )
part_rel_path=""
for dirname in new_rel_path.split("/"):
part_rel_path += f"{dirname}"
print( f"AddDir( {dirname} in {parent_dir} with {part_rel_path} as pfx ) ")
new_dir=AddDir( job, dirname, parent_dir, part_rel_path, bin_path )
parent_dir=new_dir
part_rel_path += "/"
print( f"new_dir={new_dir}" )
del_me.in_dir = new_dir
return
@@ -675,7 +700,7 @@ def JobImportDir(job):
path_obj.num_files=overall_file_cnt
parent_dir=None
# rel_path is always '' at the top of the path objects path_prefix for the first dir
# rel_path is always '' at the top of the path objects path_prefix for the first dir
dir=AddDir(job, os.path.basename(symlink), parent_dir, '', path_obj)
# session.add in case we already have imported this dir (as AddDir wont) & now we might have diff num of files to last time,
session.add(dir)
@@ -688,8 +713,8 @@ def JobImportDir(job):
# already create root above to work out num_files for whole os.walk
if root != path:
pp=SymlinkName( path_obj.type.name, path, root )+'/'+os.path.basename(root)
print( F"pp={pp}, root={root}, symlink={symlink}" )
rel_path=pp.replace(symlink+'/','')
print( f"pp={pp}, root={root}, symlink={symlink}, rel_path={rel_path}" )
dir=AddDir(job, os.path.basename(root), parent_dir, rel_path, path_obj)
for basename in files:
# commit every 100 files to see progress being made but not hammer the database
@@ -1005,8 +1030,8 @@ def RemoveDups(job):
del_me_lst = []
for f in files:
if os.path.isfile( f.FullPathOnFS() ) == False:
AddLogForJob( job, f"ERROR: (per file del) file (DB id: {f.eid} - {f.FullPathOnFS()}) does not exist? ignorning file")
elif f.file_details.eid == int(keeping):
AddLogForJob( job, f"ERROR: (per file del) file (DB id: {f.id} - {f.FullPathOnFS()}) does not exist? ignorning file")
elif f.id == int(keeping):
found = f
else:
del_me_lst.append(f)
@@ -1032,7 +1057,7 @@ def RemoveDups(job):
del_me=None
for f in files:
if os.path.isfile(f.FullPathOnFS()) == False:
AddLogForJob( job, f"ERROR: (per path del) file (DB id: {f.eid} - {f.FullPathOnFS()}) does not exist? ignorning file")
AddLogForJob( job, f"ERROR: (per path del) file (DB id: {f.id} - {f.FullPathOnFS()}) does not exist? ignorning file")
if f.in_dir.eid == int(keeping):
found=f
else:

View File

@@ -57,6 +57,7 @@
<a class="dropdown-item" href="{{url_for('files_ip')}}">View Photos to Import</a>
<a class="dropdown-item" href="{{url_for('file_list_ip')}}">View Details of Photos to Import</a>
<a class="dropdown-item" href="{{url_for('files_sp')}}">View Stored Photos</a>
<a class="dropdown-item" href="{{url_for('files_rbp')}}">View Recycle Bin</a>
</div>
</div class="nav-item dropdown">
<div class="nav-item dropdown">