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