From 4d38ac58408f6362bda36c3ceb270157ab6d04e0 Mon Sep 17 00:00:00 2001 From: Adam Goldsmith Date: Fri, 29 May 2020 17:56:09 -0400 Subject: [PATCH] Move various functionality from doorUpdater to DoorController --- memberPlumbing/doorUpdater.py | 83 ++-------------------------- memberPlumbing/hid/DoorController.py | 82 +++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 77 deletions(-) diff --git a/memberPlumbing/doorUpdater.py b/memberPlumbing/doorUpdater.py index e17040a..96e71b0 100755 --- a/memberPlumbing/doorUpdater.py +++ b/memberPlumbing/doorUpdater.py @@ -178,48 +178,14 @@ class DoorMember(Member): "custom2": self.membershipWorksID, } - def make_schedules(self, schedulesMap): - roles = [ - E.Role( - { - "roleID": self.cardholderID, - "scheduleID": schedulesMap[schedule], - "resourceID": "0", - } - ) - for schedule in self.schedules - ] - - return E.RoleSet( - {"action": "UD", "roleSetID": self.cardholderID}, E.Roles(*roles) - ) - - def make_credentials(self, newCredentials, cardFormats): - out = [ - E.Credential( - { - "formatName": str(credential.code[0]), - "cardNumber": str(credential.code[1]), - "formatID": cardFormats[str(credential.code[0])], - "isCard": "true", - "cardholderID": self.cardholderID, - } - ) - for credential in newCredentials - ] - - return E.Credentials({"action": "AD"}, *out) - def update_door(door, members): - cardFormats = door.get_cardFormats() cardholders = { member.membershipWorksID: member for member in [ DoorMember.from_cardholder(ch, door) for ch in door.get_cardholders() ] } - schedulesMap = door.get_scheduleMap() allCredentials = set( Credential(hex=c.attrib["rawCardNumber"]) for c in door.get_credentials() ) @@ -231,9 +197,7 @@ def update_door(door, members): if member.membershipWorksID not in cardholders: print("- Adding Member {member.forename} {member.surname}:") print(f" - {member.attribs()}") - resp = door.doXMLRequest( - ROOT(E.Cardholders({"action": "AD"}, E.Cardholder(member.attribs()))) - ) + resp = door.add_cardholder(member.attribs) member.cardholderID = resp.find("{*}Cardholders/{*}Cardholder").attrib[ "cardholderID" ] @@ -252,14 +216,7 @@ def update_door(door, members): print(f"- Updating profile for {member.forename} {member.surname}") print(f" - Old: {ch.attribs()}") print(f" - New: {member.attribs()}") - door.doXMLRequest( - ROOT( - E.Cardholders( - {"action": "UD", "cardholderID": member.cardholderID}, - E.CardHolder(member.attribs()), - ) - ) - ) + door.update_cardholder(member.cardholderID, member.attribs) if member.credentials != ch.credentials: print(f"- Updating card for {member.forename} {member.surname}") @@ -277,18 +234,7 @@ def update_door(door, members): # cards removed, and won't be reassigned to someone else for card in (oldCards - newCards) - allNewCards: - door.doXMLRequest( - ROOT( - E.Credentials( - { - "action": "UD", - "rawCardNumber": card.hex, - "isCard": "true", - }, - E.Credential({"cardholderID": ""}), - ) - ) - ) + door.assign_credential(card, None) if newCards - oldCards: # cards added for card in newCards & allNewCards: # new card exists in another member @@ -304,28 +250,11 @@ def update_door(door, members): # card existed in door, and needs to be reassigned for card in newCards & allCredentials: - door.doXMLRequest( - ROOT( - E.Credentials( - { - "action": "UD", - "rawCardNumber": card.hex, - "isCard": "true", - }, - E.Credential({"cardholderID": member.cardholderID}), - ) - ) - ) + door.assign_credential(card, member.cardholderID) # cards that never existed, and need to be created if newCards - allCredentials: - door.doXMLRequest( - ROOT( - member.make_credentials( - newCards - allCredentials, cardFormats - ) - ) - ) + door.add_credentials(newCards - allCredentials, member.cardholderID) if member.schedules != ch.schedules: print( @@ -333,7 +262,7 @@ def update_door(door, members): + f" {member.forename} {member.surname}:" + f" {ch.schedules} -> {member.schedules}" ) - door.doXMLRequest(ROOT(member.make_schedules(schedulesMap))) + door.set_cardholder_schedules(member.cardholderID, member.schedules) # TODO: delete cardholders that are no longer members? diff --git a/memberPlumbing/hid/DoorController.py b/memberPlumbing/hid/DoorController.py index 41e8361..f94d037 100644 --- a/memberPlumbing/hid/DoorController.py +++ b/memberPlumbing/hid/DoorController.py @@ -40,6 +40,19 @@ class DoorController: self.name = name self.access = access + # lazy evaluated, hopefully won't change for the lifetime of this object + @property + def cardFormats(self): + if not self._cardFormats: + self._cardFormats = self.get_cardFormats() + return self._cardFormats + + @property + def schedulesMap(self): + if not self._schedulesMap: + self._schedulesMap = self.get_schedulesMap() + return self._schedulesMap + def doImport(self, params=None, files=None): """Send a request to the door control import script""" r = requests.post( @@ -131,6 +144,24 @@ class DoorController: # load new schedules self.doXMLRequest(schedules) + def set_cardholder_schedules(self, cardholderID, schedules): + roles = [ + E.Role( + { + "roleID": cardholderID, + "scheduleID": self.schedulesMap[schedule], + "resourceID": "0", + } + ) + for schedule in schedules + ] + + roleSet = E.RoleSet( + {"action": "UD", "roleSetID": cardholderID}, E.Roles(*roles) + ) + + return self.doXMLRequest(ROOT(roleSet)) + def get_cardFormats(self): cardFormats = self.doXMLRequest( ROOT(E.CardFormats({"action": "LR", "responseFormat": "expanded"})) @@ -192,9 +223,60 @@ class DoorController: def get_cardholders(self): return self.get_records(E.Cardholders, 1000, {"responseFormat": "expanded"}) + def add_cardholder(self, attribs): + return self.doXMLRequest( + ROOT(E.Cardholders({"action": "AD"}, E.Cardholder(attribs))) + ) + + def update_cardholder(self, cardholderID, attribs): + return self.doXMLRequest( + ROOT( + E.Cardholders( + {"action": "UD", "cardholderID": cardholderID}, + E.CardHolder(attribs), + ) + ) + ) + def get_credentials(self): return self.get_records(E.Credentials, 1000) + def add_credentials(self, credentials, cardholderID=None): + """Create new Credentials. If a cardholderID is provided, assign the + new credentials to that cardholder""" + creds = [ + E.Credential( + { + "formatName": str(credential.code[0]), + "cardNumber": str(credential.code[1]), + "formatID": self.cardFormats[str(credential.code[0])], + "isCard": "true", + **({"cardholderID": cardholderID} if cardholderID else {}), + } + ) + for credential in credentials + ] + + return self.doXMLRequest(ROOT(E.Credentials({"action": "AD"}, *creds))) + + def assign_credential(self, credential, cardholderID=None): + # empty string removes assignment + if cardholderID is None: + cardholderID = "" + + return self.doXMLRequest( + ROOT( + E.Credentials( + { + "action": "UD", + "rawCardNumber": credential.hex, + "isCard": "true", + }, + E.Credential({"cardholderID": cardholderID}), + ) + ) + ) + def get_events(self, threshold): def event_newer_than_threshold(event): return datetime.fromisoformat(event.attrib["timestamp"]) > threshold