first pass at keeping overrides on face delete - should at least stop code crashing if you try to delete faces from DB and they still had a matching override

This commit is contained in:
2022-07-28 21:23:34 +10:00
parent 96810fa1e3
commit 391b61f3c4
5 changed files with 135 additions and 16 deletions

View File

@@ -1,4 +1,4 @@
###
#
#
# This file controls the 'external' job control manager, that (periodically #
# looks / somehow is pushed an event?) picks up new jobs, and processes them.
@@ -360,6 +360,79 @@ class FaceRefimgLink(Base):
def __repr__(self):
return f"<face_id: {self.face_id}, refimg_id={self.refimg_id}"
################################################################################
# Class describing types of non-match overrides for faces
################################################################################
class FaceOverrideType(Base):
__tablename__ = "face_override_type"
id = Column(Integer, Sequence('face_override_type_id_seq'), primary_key=True )
name = Column( String )
def __repr__(self):
return f"<id: {self.id}, name={self.name}>"
################################################################################
# Class containing which faces are not ever allowed to match (and the
# type/reason why)
################################################################################
class FaceNoMatchOverride(Base):
__tablename__ = "face_no_match_override"
id = Column(Integer, Sequence('face_override_id_seq'), primary_key=True )
face_id = Column(Integer, ForeignKey("face.id"), primary_key=True )
type_id = Column(Integer, ForeignKey("face_override_type.id"))
type = relationship("FaceOverrideType")
def __repr__(self):
return f"<id: {self.id}, face_id={self.face_id}, type: {self.type}>"
################################################################################
# Class containing a manual / forced match of a face in a file to a person
################################################################################
class FaceManualOverride(Base):
__tablename__ = "face_manual_override"
id = Column(Integer, Sequence('face_override_id_seq'), primary_key=True )
face_id = Column(Integer, ForeignKey("face.id"), primary_key=True )
person_id = Column(Integer, ForeignKey("person.id"), primary_key=True )
person = relationship("Person")
def __repr__(self):
return f"<id: {self.id}, face_id={self.face_id}, person_id={self.person_id}>"
################################################################################
# Class describing DisconnectedNoMatchOverride in the database and DB via
# sqlalchemy - Used when a face with an override is deleted from the DB to keep
# the raw data so that we can reconnect the override if we ever scan that same
# file/face again (think delete/undelete file, rebuild DB from file sys/from
# scratch, etc)
# used specifically for a face that should not ever be a match
################################################################################
class DisconnectedNoMatchOverride(Base):
__tablename__ = "disconnected_no_match_override"
face = Column( LargeBinary, primary_key=True )
type_id = Column(Integer, ForeignKey("face_override_type.id"))
def __repr__(self):
return f"<face: {self.face}, type_id={self.type_id}"
################################################################################
# Class describing DisconnectedManualOverride in the database and DB via
# sqlalchemy - Used when a face with an override is deleted from the DB to keep
# the raw data so that we can reconnect the override if we ever scan that same
# file/face again (think delete/undelete file, rebuild DB from file sys/from
# scratch, etc)
# used specifically for a match that was forced between a face and a person
################################################################################
class DisconnectedManualOverride(Base):
__tablename__ = "disconnected_manual_override"
face = Column( LargeBinary, primary_key=True )
person_id = Column(Integer, ForeignKey('person.id'))
def __repr__(self):
return f"<face: {self.face}, person_id={self.person_id}"
################################################################################
# Class describing logs for each job and via sqlalchemy, connected to the DB as well
################################################################################
@@ -828,12 +901,36 @@ def JobScanStorageDir(job):
MessageToFE( job.id, "success", "Completed (scan for new files)" )
return
##############################################################################
# All face Overrides should not just be deleted, they should be disconnected
# from the file (in face_file_link), but instead keep the raw face data so
# that a face that is found in a future scan can still keep the override
# connection
##############################################################################
def DisconnectAllOverrides():
overrides=session.query(FaceNoMatchOverride).all()
for o in overrides:
f=session.query(Face).get(o.face_id)
session.add( DisconnectedNoMatchOverride( face=f.face, type_id=o.type_id ) )
overrides=session.query(FaceNoMatchOverride).delete()
overrides=session.query(FaceManualOverride).all()
for o in overrides:
f=session.query(Face).get(o.face_id)
session.add( DisconnectedManualOverride( face=f.face, person_id=o.person_id ) )
overrides=session.query(FaceManualOverride).delete()
session.commit()
return
##############################################################################
# JobForceScan(): start and process the job to force scanning now - so delete
# all attached data in DB, then scan import and storage paths
##############################################################################
def JobForceScan(job):
JobProgressState( job, "In Progress" )
DisconnectAllOverrides()
session.query(PA_UserState).delete()
session.query(FaceFileLink).delete()
session.query(FaceRefimgLink).delete()
@@ -1984,7 +2081,23 @@ def DelMatchesForFile( job, ent ):
# DelFacesForFile(): quick func to delete any faces associated with the specified file
####################################################################################################################################
def DelFacesForFile( eid ):
ffl=session.query(FaceFileLink).filter(FaceFileLink.file_eid==eid).all()
for link in ffl:
# find any manaul overrides on this face (before we delete it, and put them into the disc* table)
o=session.query(FaceManualOverride).filter(FaceManualOverride.face_id==link.face_id).one()
if o:
f=session.query(Face).get(link.face_id)
session.add( DisconnectedManualOverride( face=f.face, person_id=o.person_id ) )
# find any no-match overrides on this face (before we delete it, and put them into the disc* table)
o=session.query(FaceNoMatchOverride).filter(FaceNoMatchOverride.face_id==link.face_id).one()
if o:
f=session.query(Face).get(link.face_id)
session.add( DisconnectedNoMatchOverride( face=f.face, type_id=o.type_id ) )
session.execute( f"delete from face where id in (select face_id from face_file_link where file_eid = {eid})" )
session.commit()
return