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:
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user