diff --git a/pa_job_manager.py b/pa_job_manager.py index 81831b9..7544559 100644 --- a/pa_job_manager.py +++ b/pa_job_manager.py @@ -174,6 +174,15 @@ class File(Base): def __repr__(self): return f"" +class DelFile(Base): + __tablename__ = "del_file" + file_eid = Column(Integer, ForeignKey("file.eid"), primary_key=True ) + orig_path_prefix = Column(String, unique=False ) + + def __repr__(self): + return f"" + + class FileType(Base): __tablename__ = "file_type" id = Column(Integer, Sequence('file_type_id_seq'), primary_key=True ) @@ -473,6 +482,7 @@ def JobScanStorageDir(job): def JobForceScan(job): JobProgressState( job, "In Progress" ) + session.query(DelFile).delete() session.query(FileRefimgLink).delete() session.query(EntryDirLink).delete() session.query(PathDirLink).delete() @@ -594,7 +604,49 @@ def RemoveFileFromFS( del_me ): print( f"ERROR: Failed to remove file from filesystem - which={src}, err: {e}") return -# Functoin that moves a file we are "deleting" to the recycle bin, it moves the +# Function that undeletes a file that was deleted (moved into the Bin) +# it moves file on the filesystem back to its original path and then changes the database path from the Bin path +# to the original import or storage path and appropriate dir +def UnDeleteFile(job,restore_me): + try: + # rel_path for a file in the Bin, is like 'Import/images_to_process/1111', so just prepend static/ + dst_dir='static/' + restore_me.in_dir.rel_path + '/' + os.makedirs( dst_dir,mode=0o777, exist_ok=True ) + src=restore_me.FullPathOnFS() + dst=dst_dir + '/' + restore_me.name + os.replace( src, dst ) + except Exception as e: + print( f"ERROR: Failed to undelete (mv) file on filesystem - which={src} to {dst}, err: {e}") + + # need these for AddDir calls below to work + orig_file_details = session.query(DelFile).get(restore_me.id) + orig_path = session.query(Path).filter(Path.path_prefix==orig_file_details.orig_path_prefix).first() + parent_dir=session.query(Dir).join(PathDirLink).filter(PathDirLink.path_id==orig_path.id).first() + + # e.g. restore_me's rel_path 'Import/images_to_process/1111', orig_path was 'static/Import/images_to_process', need new rel_path to be just the 1111 bit... + new_rel_path='static/'+restore_me.in_dir.rel_path + new_rel_path=new_rel_path.replace(orig_file_details.orig_path_prefix+'/', '') + new_rel_path='1111' + + # okay, go through new relative path and AddDir any missing subdirs of this + # path (think Import/Dir1/Dir2) which b/c we have orig_path in AddDir will + # create static/Import, static/Import/Dir1, static/Import/Dir1/Dir2 + part_rel_path="" + for dirname in new_rel_path.split("/"): + part_rel_path += f"{dirname}" + ### DDP: when restoring, an original dir might have been removed, so need make it (if needed) + os.makedirs( dirname,mode=0o777, exist_ok=True ) + new_dir=AddDir( job, dirname, parent_dir, part_rel_path, orig_path ) + parent_dir=new_dir + part_rel_path += "/" + + restore_me.in_dir = new_dir + session.query(DelFile).filter(DelFile.file_eid==restore_me.id).delete() + session.commit() + print("TODO: enqueue check_dups job") + return + +# Function that moves a file we are "deleting" to the recycle bin, it moves the # file on the filesystem and then changes the database path from the import or # storage path over to the Bin path def MoveFileToRecycleBin(job,del_me): @@ -607,14 +659,26 @@ def MoveFileToRecycleBin(job,del_me): os.replace( src, dst ) except Exception as e: print( f"ERROR: Failed to remove file from filesystem - which={src}, err: {e}") - bin_path=session.query(Path).join(PathType).filter(PathType.name=='Bin').first() - new_rel_path=del_me.in_dir.in_path.path_prefix.replace('static/','') + # need these for AddDir calls below to work + bin_path=session.query(Path).join(PathType).filter(PathType.name=='Bin').first() + parent_dir=session.query(Dir).join(PathDirLink).filter(PathDirLink.path_id==bin_path.id).first() + + print( f"need to keep this (ind): {del_me.in_dir.in_path.path_prefix}" ) + # if we ever need to undelete, lets remember this file's original path + # (use a string in case the dir/path is ever deleted from FS (and then DB) and we need to recreate) + del_file_details = DelFile( file_eid=del_me.id, orig_path_prefix=del_me.in_dir.in_path.path_prefix ) + session.add( del_file_details ) + + # remove static from rel path, as it will move to static/Bin anyway... + 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 - parent_dir=session.query(Dir).join(PathDirLink).filter(PathDirLink.path_id==bin_path.id).first() + # okay, go through new relative path and AddDir any missing subdirs of this + # path (think Import/Dir1/Dir2) which b/c we have bin_path in AddDir will + # create Bin/Import, Bin/Import/Dir1, Bin/Import/Dir1/Dir2 part_rel_path="" for dirname in new_rel_path.split("/"): part_rel_path += f"{dirname}" @@ -1139,10 +1203,10 @@ if __name__ == "__main__": ValidateSettingsPaths() -# now=datetime.now(pytz.utc) -# job=Job(start_time=now, last_update=now, name="scannow", state="New", wait_for=None, pa_job_state="New", current_file_num=0, num_files=0 ) -# session.add(job) -# session.commit() +# restore_me=session.query(Entry).join(File).join(DelFile).first() +# if restore_me: +# UnDeleteFile(Job(),restore_me) + HandleJobs() with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((PA_JOB_MANAGER_HOST, PA_JOB_MANAGER_PORT))