2018-05-09 21:26:20 -04:00
|
|
|
#!/usr/bin/env python3
|
2018-05-08 16:01:15 -04:00
|
|
|
import sys
|
2018-05-07 18:02:04 -04:00
|
|
|
import requests
|
|
|
|
import csv
|
|
|
|
from io import StringIO
|
2018-05-10 11:12:51 -04:00
|
|
|
from hashlib import md5
|
|
|
|
import os
|
2018-05-07 18:02:04 -04:00
|
|
|
|
2018-05-12 09:49:51 -04:00
|
|
|
from common import *
|
2018-05-07 18:02:04 -04:00
|
|
|
|
2018-05-07 18:25:14 -04:00
|
|
|
# mapping of member levels to schedules
|
2018-05-07 18:02:04 -04:00
|
|
|
memberLevels = {"CMS Staff": "7x24",
|
|
|
|
"CMS Weekends Only": "Weekends Only",
|
|
|
|
"CMS Weekdays Only": "Weekdays Only",
|
|
|
|
"CMS Unlimited": "Unlimited",
|
|
|
|
"CMS Nights & Weekends": "Nights and Weekends"}
|
|
|
|
|
|
|
|
def getMembershipworksData():
|
2018-05-07 18:25:14 -04:00
|
|
|
""" Pull the members csv from the membershipworks api """
|
2018-05-07 18:02:04 -04:00
|
|
|
BASE_URL = "https://api.membershipworks.com/v1/"
|
|
|
|
|
2018-05-07 18:25:14 -04:00
|
|
|
# login
|
2018-05-08 15:59:27 -04:00
|
|
|
r = requests.post(BASE_URL + 'usr',
|
|
|
|
data={"_st": "all",
|
|
|
|
"eml": MEMBERSHIPWORKS_USERNAME,
|
|
|
|
"org": "10000",
|
|
|
|
"pwd": MEMBERSHIPWORKS_PASSWORD})
|
2018-05-08 16:01:15 -04:00
|
|
|
if r.status_code != 200 or 'SF' not in r.json():
|
|
|
|
print("MembershipWorks Login Error: ", r.status_code, r.reason)
|
|
|
|
print(r.text)
|
|
|
|
sys.exit(1)
|
2018-05-07 18:02:04 -04:00
|
|
|
SFtoken = r.json()['SF']
|
|
|
|
|
2018-05-07 18:25:14 -04:00
|
|
|
# get list of member/staff IDs
|
2018-05-08 15:59:27 -04:00
|
|
|
r = requests.get(BASE_URL + "ylp",
|
|
|
|
params={"SF": SFtoken,
|
|
|
|
"lbl": "5ae37979f033bfe8534f8799,5771675edcdf126302a2f6b9", # members and staff
|
|
|
|
"org": "15475", # unknown
|
|
|
|
"var": "_id,nam,ctc"})
|
2018-05-08 16:01:15 -04:00
|
|
|
if r.status_code != 200 or 'usr' not in r.json():
|
|
|
|
print("MembershipWorks User Listing Error: ", r.status_code, r.reason)
|
|
|
|
print(r.text)
|
|
|
|
sys.exit(1)
|
2018-05-07 18:02:04 -04:00
|
|
|
ids = [user['_id'] for user in r.json()['usr']]
|
|
|
|
|
2018-05-07 18:25:14 -04:00
|
|
|
# get members CSV
|
|
|
|
# TODO: maybe can just use previous get instead? would return JSON
|
2018-05-08 15:59:27 -04:00
|
|
|
r = requests.post(BASE_URL + "csv",
|
|
|
|
params={"SF": SFtoken},
|
|
|
|
data={"_rt": "946702800", # unknown
|
|
|
|
"mux": "", # unknown
|
|
|
|
"tid": ",".join(ids), # ids of members to get
|
2018-06-03 14:16:32 -04:00
|
|
|
"var": "lvl,xws,xms,xsc,xas,xfd,xac,phn,eml,lbl,xcf,nam"}) # which columns to get
|
2018-05-08 16:01:15 -04:00
|
|
|
if r.status_code != 200:
|
|
|
|
print("MembershipWorks CSV Generation Error: ", r.status_code, r.reason)
|
|
|
|
print(r.text)
|
|
|
|
sys.exit(1)
|
2018-05-07 18:02:04 -04:00
|
|
|
|
2018-06-02 14:37:53 -04:00
|
|
|
return r.text
|
2018-05-07 18:02:04 -04:00
|
|
|
|
|
|
|
def makeMember(member, doorAuth):
|
2018-05-07 18:25:14 -04:00
|
|
|
"""Create an output CSV row for the member"""
|
2018-05-07 18:02:04 -04:00
|
|
|
if member["Access Card Number"] == "":
|
|
|
|
#print(member["First Name"], member["Last Name"], " has no card number, ignoring")
|
|
|
|
return
|
|
|
|
|
|
|
|
out = {"Forename": member["First Name"],
|
2018-05-07 18:25:14 -04:00
|
|
|
"Surname": member["Last Name"],
|
|
|
|
"Initial": "",
|
|
|
|
"CardNumber": member["Access Card Number"],
|
2018-05-08 20:35:33 -04:00
|
|
|
"CardFormat": "A901146A-" + member["Access Card Facility Code"],
|
2018-05-07 18:25:14 -04:00
|
|
|
"PinRequired": "0",
|
|
|
|
"ExtendedAccess": "0",
|
|
|
|
"ExpiryDate": "",
|
|
|
|
"Email": member["Email"],
|
|
|
|
"Phone": member["Phone"]}
|
2018-05-07 18:02:04 -04:00
|
|
|
|
2018-05-08 20:27:32 -04:00
|
|
|
if member[doorAuth] == "Y" \
|
|
|
|
and not member["Account on Hold"] == "Account on Hold":
|
2018-06-01 13:59:43 -04:00
|
|
|
levels = {k: v for k, v in memberLevels.items() if member[k] == k}
|
|
|
|
out["Custom1"] = "|".join(levels.keys()).replace("&", "and")
|
|
|
|
for index, schedule in enumerate(levels.values(), 1):
|
|
|
|
#TODO: error if people have more than 8?
|
|
|
|
out["Schedule" + str(index)] = schedule
|
2018-05-07 18:02:04 -04:00
|
|
|
|
|
|
|
return out
|
|
|
|
|
2018-06-03 14:24:46 -04:00
|
|
|
def makeDoor(doorName, doorData, members, hashes):
|
2018-05-07 18:25:14 -04:00
|
|
|
"""Create a CSV for the given door"""
|
2018-05-07 18:02:04 -04:00
|
|
|
outString = StringIO()
|
|
|
|
writer = csv.DictWriter(outString, fieldnames)
|
|
|
|
writer.writeheader()
|
|
|
|
for member in members:
|
2018-05-27 17:17:36 -04:00
|
|
|
member = makeMember(member, "Access " + doorData["access"] + "?")
|
2018-05-07 18:02:04 -04:00
|
|
|
if member is not None:
|
|
|
|
writer.writerow(member)
|
|
|
|
|
|
|
|
print(outString.getvalue())
|
2018-05-27 17:17:36 -04:00
|
|
|
|
|
|
|
outString.seek(0)
|
2018-06-02 14:37:53 -04:00
|
|
|
doorHash = md5(bytes(outString.getvalue(), 'utf8')).hexdigest()
|
2018-06-03 14:24:46 -04:00
|
|
|
if doorHash == hashes.get(doorName):
|
2018-06-02 14:37:53 -04:00
|
|
|
print("Door", doorName, "not changed, not updating")
|
|
|
|
else:
|
2018-06-03 14:24:46 -04:00
|
|
|
hashes[doorName] = doorHash
|
2018-06-02 14:37:53 -04:00
|
|
|
doCSVImport(doorData["ip"], outString)
|
2018-06-03 14:24:46 -04:00
|
|
|
# write out hash if we sucessfully updated this door
|
|
|
|
with open('/tmp/doorUpdaterLastHash', 'w') as f:
|
|
|
|
json.dump(hashes, f)
|
2018-05-07 18:02:04 -04:00
|
|
|
|
|
|
|
def main():
|
2018-06-02 14:37:53 -04:00
|
|
|
data = getMembershipworksData()
|
2018-05-07 18:02:04 -04:00
|
|
|
reader = csv.DictReader(StringIO(data))
|
|
|
|
members = list(reader)
|
|
|
|
|
2018-06-02 14:37:53 -04:00
|
|
|
if os.path.exists('/tmp/doorUpdaterLastHash'):
|
|
|
|
with open('/tmp/doorUpdaterLastHash', 'r') as f:
|
|
|
|
hashes = json.load(f)
|
|
|
|
else:
|
|
|
|
hashes = {}
|
|
|
|
|
2018-05-27 17:17:36 -04:00
|
|
|
for doorName, doorData in config["doors"].items():
|
|
|
|
print(doorName, doorData)
|
2018-06-03 14:24:46 -04:00
|
|
|
makeDoor(doorName, doorData, members, hashes)
|
2018-05-11 19:03:29 -04:00
|
|
|
|
2018-05-07 18:02:04 -04:00
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|