Refactor new XML updater, move methods into correct classes
This commit is contained in:
parent
bb18f34b2e
commit
667260831c
@ -26,7 +26,7 @@ class DoorController():
|
||||
self.name = name
|
||||
self.access = access
|
||||
|
||||
def doImportRequest(self, params=None, files=None):
|
||||
def doImport(self, params=None, files=None):
|
||||
"""Send a request to the door control import script"""
|
||||
r = requests.post(
|
||||
'https://' + self.ip + '/cgi-bin/import.cgi',
|
||||
@ -42,10 +42,10 @@ class DoorController():
|
||||
|
||||
def doCSVImport(self, csv):
|
||||
"""Do the CSV import procedure on a door control"""
|
||||
self.doImportRequest({"task": "importInit"})
|
||||
self.doImportRequest({"task": "importCardsPeople", "name": "cardspeopleschedule.csv"},
|
||||
self.doImport({"task": "importInit"})
|
||||
self.doImport({"task": "importCardsPeople", "name": "cardspeopleschedule.csv"},
|
||||
{"importCardsPeopleButton": ("cardspeopleschedule.csv", csv, 'text/csv')})
|
||||
self.doImportRequest({"task": "importDone"})
|
||||
self.doImport({"task": "importDone"})
|
||||
|
||||
def doXMLRequest(self, xml, prefix=b'<?xml version="1.0" encoding="UTF-8"?>'):
|
||||
if not isinstance(xml, bytes):
|
||||
@ -62,7 +62,28 @@ class DoorController():
|
||||
raise RemoteError(r)
|
||||
return resp_xml
|
||||
|
||||
def sendSchedules(self, schedules):
|
||||
def get_scheduleMap(self):
|
||||
schedules = self.doXMLRequest(
|
||||
ROOT(E.Schedules({"action": "LR",
|
||||
"recordOffset": "0",
|
||||
"recordCount": "8"})))
|
||||
return {fmt.attrib["scheduleName"]: fmt.attrib["scheduleID"]
|
||||
for fmt in schedules[0]}
|
||||
|
||||
def get_schedules(self):
|
||||
# TODO: might be able to do in one request
|
||||
schedules = self.doXMLRequest(ROOT(
|
||||
E.Schedules({"action": "LR"})))
|
||||
etree.dump(schedules)
|
||||
|
||||
data = self.doXMLRequest(ROOT(
|
||||
*[E.Schedules({"action": "LR",
|
||||
"scheduleID": schedule.attrib["scheduleID"]})
|
||||
for schedule in schedules[0]]))
|
||||
return ROOT(E_corp.Schedules({"action": "AD"},
|
||||
*[s[0] for s in data]))
|
||||
|
||||
def set_schedules(self, schedules):
|
||||
# clear all people
|
||||
outString = StringIO()
|
||||
writer = csv.DictWriter(outString, fieldnames)
|
||||
@ -84,20 +105,15 @@ class DoorController():
|
||||
# load new schedules
|
||||
self.doXMLRequest(schedules)
|
||||
|
||||
def getSchedules(self):
|
||||
# TODO: might be able to do in one request
|
||||
schedules = self.doXMLRequest(ROOT(
|
||||
E.Schedules({"action": "LR"})))
|
||||
etree.dump(schedules)
|
||||
def get_cardFormats(self):
|
||||
cardFormats = self.doXMLRequest(
|
||||
ROOT(E.CardFormats({"action": "LR",
|
||||
"responseFormat": "expanded"})))
|
||||
|
||||
data = self.doXMLRequest(ROOT(
|
||||
*[E.Schedules({"action": "LR",
|
||||
"scheduleID": schedule.attrib["scheduleID"]})
|
||||
for schedule in schedules[0]]))
|
||||
return ROOT(E_corp.Schedules({"action": "AD"},
|
||||
*[s[0] for s in data]))
|
||||
return {fmt[0].attrib["value"]: fmt.attrib["formatID"]
|
||||
for fmt in cardFormats[0].findall('{*}CardFormat[{*}FixedField]')}
|
||||
|
||||
def sendCardFormat(self, formatName, templateID, facilityCode):
|
||||
def set_cardFormat(self, formatName, templateID, facilityCode):
|
||||
# TODO: add ability to delete formats
|
||||
# delete example: <hid:CardFormats action="DD" formatID="7-1-244"/>
|
||||
|
||||
@ -108,15 +124,22 @@ class DoorController():
|
||||
E.FixedField({"value": str(facilityCode)}))))
|
||||
return self.doXMLRequest(el)
|
||||
|
||||
def lockOrUnlockDoor(self, lock=True):
|
||||
el = ROOT(
|
||||
E.Doors({"action": "CM",
|
||||
"command": "lockDoor" if lock else "unlockDoor"}))
|
||||
return self.doXMLRequest(el)
|
||||
def get_cardholders(self):
|
||||
return self.doXMLRequest(
|
||||
ROOT(E.Cardholders({"action": "LR",
|
||||
"responseFormat": "expanded",
|
||||
"recordOffset": "0",
|
||||
"recordCount": "1000"})))[0]
|
||||
|
||||
def getStatus(self):
|
||||
def get_lock(self):
|
||||
el = ROOT(
|
||||
E.Doors({"action": "LR", "responseFormat": "status"}))
|
||||
xml = self.doXMLRequest(el)
|
||||
relayState = xml.find('./{*}Doors/{*}Door').attrib['relayState']
|
||||
return "unlocked" if relayState == "set" else "locked"
|
||||
|
||||
def set_lock(self, lock=True):
|
||||
el = ROOT(
|
||||
E.Doors({"action": "CM",
|
||||
"command": "lockDoor" if lock else "unlockDoor"}))
|
||||
return self.doXMLRequest(el)
|
||||
|
102
new_xml_based.py
102
new_xml_based.py
@ -83,78 +83,56 @@ Schedules: {self.schedules}
|
||||
schedules=list(levels.values()))
|
||||
|
||||
def attribs(self):
|
||||
out = {"forename": self.forename,
|
||||
"surname": self.surname,
|
||||
"middleName": self.middleName,
|
||||
"email": self.email,
|
||||
"phone": self.phone,
|
||||
"custom1": "|".join(self.levels).replace("&", "and"),
|
||||
"custom2": self.membershipWorksID}
|
||||
return out
|
||||
return {"forename": self.forename,
|
||||
"surname": self.surname,
|
||||
"middleName": self.middleName,
|
||||
"email": self.email,
|
||||
"phone": self.phone,
|
||||
"custom1": "|".join(self.levels).replace("&", "and"),
|
||||
"custom2": self.membershipWorksID}
|
||||
|
||||
def make_roles(self, door, schedulesMap):
|
||||
def schedulesForDoor(self, door):
|
||||
if door.name not in self.doorAccess or self.onHold:
|
||||
return []
|
||||
else:
|
||||
return self.schedules
|
||||
|
||||
for schedule in self.schedules:
|
||||
yield E.Role({"roleID": self.cardholderID,
|
||||
"scheduleID": schedulesMap[schedule],
|
||||
"resourceID": "0"})
|
||||
def make_schedules(self, door, schedulesMap):
|
||||
roles = [
|
||||
E.Role({"roleID": self.cardholderID,
|
||||
"scheduleID": schedulesMap[schedule],
|
||||
"resourceID": "0"})
|
||||
for schedule in self.schedulesForDoor(door)]
|
||||
|
||||
return E.RoleSet({"action": "UD", "roleSetID": self.cardholderID},
|
||||
E.Roles(*roles))
|
||||
|
||||
def make_credentials(self, cardFormats):
|
||||
for credential in self.credentials:
|
||||
yield E.Credential(
|
||||
credentials = [
|
||||
E.Credential(
|
||||
{"formatName": credential[0],
|
||||
"cardNumber": credential[1],
|
||||
"formatID": cardFormats[credential[0]],
|
||||
"isCard": "true",
|
||||
"cardholderID": self.cardholderID})
|
||||
for credential in self.credentials]
|
||||
|
||||
def get_cardholders(door, cardFormats):
|
||||
cardholders = door.doXMLRequest(
|
||||
ROOT(E.Cardholders({"action": "LR",
|
||||
"responseFormat": "expanded",
|
||||
"recordOffset": "0",
|
||||
"recordCount": "1000"})))
|
||||
return E.Credentials({"action": "AD"}, *credentials)
|
||||
|
||||
for cardholder in cardholders[0]:
|
||||
yield Member.from_cardholder(cardholder, cardFormats)
|
||||
|
||||
def get_cardFormats(door):
|
||||
cardFormats = door.doXMLRequest(
|
||||
ROOT(E.CardFormats({"action": "LR",
|
||||
"responseFormat": "expanded"})))
|
||||
|
||||
return {fmt[0].attrib["value"]: fmt.attrib["formatID"]
|
||||
for fmt in cardFormats[0].findall('{*}CardFormat[{*}FixedField]')}
|
||||
|
||||
def get_schedules(door):
|
||||
schedules = door.doXMLRequest(
|
||||
ROOT(E.Schedules({"action": "LR",
|
||||
"recordOffset": "0",
|
||||
"recordCount": "8"})))
|
||||
return {fmt.attrib["scheduleName"]: fmt.attrib["scheduleID"]
|
||||
for fmt in schedules[0]}
|
||||
|
||||
def update_credentials(member, cardFormats):
|
||||
return E.Credentials({"action": "AD"}, *member.make_credentials(cardFormats))
|
||||
|
||||
def update_schedules(member, door, schedulesMap):
|
||||
return E.RoleSet({"action": "UD", "roleSetID": member.cardholderID},
|
||||
E.Roles(*member.make_roles(door, schedulesMap)))
|
||||
|
||||
def update_door(door, members):
|
||||
cardFormats = get_cardFormats(door)
|
||||
cardholders = {ch.membershipWorksID: ch
|
||||
for ch in get_cardholders(door, cardFormats)}
|
||||
schedulesMap = get_schedules(door)
|
||||
cardFormats = door.get_cardFormats()
|
||||
cardholders = {member.membershipWorksID: member
|
||||
for member in [Member.from_cardholder(ch, cardFormats)
|
||||
for ch in door.get_cardholders()]}
|
||||
schedulesMap = door.get_scheduleMap()
|
||||
|
||||
for member in members:
|
||||
# TODO: can I combine requests?
|
||||
if member.membershipWorksID in cardholders: # cardholder exists, compare contents
|
||||
ch = cardholders.pop(member.membershipWorksID)
|
||||
member.cardholderID = ch.cardholderID
|
||||
if member.attribs() != ch.attribs(): # update cardholder
|
||||
if member.attribs() != ch.attribs(): # update cardholder attributes
|
||||
print(f"- Updating profile for {member.forename} {member.surname}")
|
||||
print(f" - Old: {ch.attribs()}")
|
||||
print(f" - New: {member.attribs()}")
|
||||
@ -162,19 +140,18 @@ def update_door(door, members):
|
||||
E.Cardholders(
|
||||
{"action": "UD", "cardholderID": member.cardholderID},
|
||||
E.CardHolder(member.attribs()))))
|
||||
|
||||
if member.credentials != ch.credentials:
|
||||
print(f"- Updating card for {member.forename} {member.surname}")
|
||||
print(f" - {ch.credentials} -> {member.credentials}")
|
||||
door.doXMLRequest(ROOT(update_credentials(member, cardFormats)))
|
||||
door.doXMLRequest(ROOT(member.make_credentials(cardFormats)))
|
||||
|
||||
# TODO: might not handle people on hold correctly?
|
||||
schedulesForDoor = member.schedules if door.name in member.doorAccess else []
|
||||
if schedulesForDoor != ch.schedules:
|
||||
if member.schedulesForDoor(door) != ch.schedules:
|
||||
print("- Updating schedule for" +
|
||||
f" {member.forename} {member.surname}:" +
|
||||
f" {ch.schedules} -> {member.schedules}")
|
||||
door.doXMLRequest(ROOT(update_schedules(member, door, schedulesMap)))
|
||||
else: # do add
|
||||
f" {ch.schedules} -> {member.schedulesForDoor(door)}")
|
||||
door.doXMLRequest(ROOT(member.make_schedules(door, schedulesMap)))
|
||||
else: # cardholder did not exist, so add them
|
||||
print(f"- Adding Member:")
|
||||
print(member)
|
||||
resp = door.doXMLRequest(ROOT(
|
||||
@ -182,8 +159,8 @@ def update_door(door, members):
|
||||
E.Cardholder(member.attribs()))))
|
||||
member.cardholderID = resp.find('{*}Cardholders/{*}Cardholder') \
|
||||
.attrib["cardholderID"]
|
||||
door.doXMLRequest(ROOT(update_credentials(member, cardFormats),
|
||||
update_schedules(member, door, schedulesMap)))
|
||||
door.doXMLRequest(ROOT(member.make_credentials(cardFormats),
|
||||
member.update_schedules(door, schedulesMap)))
|
||||
|
||||
# TODO: delete cardholders that are no longer members?
|
||||
|
||||
@ -198,9 +175,4 @@ def main():
|
||||
print(door.name, door.ip)
|
||||
update_door(door, members)
|
||||
|
||||
# m = Member("test", "test", membershipWorksID="5af07954afd691b84c15a24d",
|
||||
# credentials=[("A901146A-241", "20178")],
|
||||
# schedules=["15:00-24:00"],
|
||||
# doorAccess=["Front Door"])
|
||||
# update_door(doors["Front Door"], [m])
|
||||
main()
|
||||
|
Reference in New Issue
Block a user