2018-06-19 18:24:15 -04:00
|
|
|
import csv
|
2018-05-27 17:17:36 -04:00
|
|
|
import json
|
2018-05-12 09:49:51 -04:00
|
|
|
import urllib3
|
2018-08-13 15:46:00 -04:00
|
|
|
import os
|
2018-06-03 14:26:58 -04:00
|
|
|
import sys
|
2018-06-19 18:24:15 -04:00
|
|
|
from io import StringIO
|
2018-05-12 09:49:51 -04:00
|
|
|
from xml.etree import ElementTree as ET
|
|
|
|
import requests
|
|
|
|
|
|
|
|
from passwords import *
|
|
|
|
|
|
|
|
# it's fine, ssl certs are for losers anyway
|
|
|
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
|
|
|
2018-08-13 15:46:00 -04:00
|
|
|
config = json.load(
|
|
|
|
open(os.path.dirname(os.path.abspath(__file__)) + "/config.json"))
|
2018-05-27 17:17:36 -04:00
|
|
|
|
2018-05-14 22:36:24 -04:00
|
|
|
ET.register_namespace("hid", "http://www.hidglobal.com/VertX")
|
|
|
|
ET.register_namespace("hid", "http://www.hidcorp.com/VertX")
|
|
|
|
|
2018-05-12 09:49:51 -04:00
|
|
|
fieldnames = "CardNumber,CardFormat,PinRequired,PinCode,ExtendedAccess,ExpiryDate,Forename,Initial,Surname,Email,Phone,Custom1,Custom2,Schedule1,Schedule2,Schedule3,Schedule4,Schedule5,Schedule6,Schedule7,Schedule8".split(",")
|
|
|
|
|
2018-08-07 18:33:12 -04:00
|
|
|
def getMembershipworksData(folders, columns):
|
2018-06-19 18:24:15 -04:00
|
|
|
""" Pull the members csv from the membershipworks api
|
2018-08-07 18:33:12 -04:00
|
|
|
folders: a list of the names of the folders to get
|
|
|
|
(see folder_map in this function for mapping to ids)
|
2018-06-19 18:24:15 -04:00
|
|
|
columns: which columns to get"""
|
|
|
|
BASE_URL = "https://api.membershipworks.com/v1/"
|
2018-08-07 18:33:12 -04:00
|
|
|
folder_map = {'members': '5ae37979f033bfe8534f8799',
|
|
|
|
'staff': '5771675edcdf126302a2f6b9',
|
|
|
|
'misc': '5b69ee9bf033bf8e7346c434'}
|
2018-06-19 18:24:15 -04:00
|
|
|
|
|
|
|
# login
|
|
|
|
r = requests.post(BASE_URL + 'usr',
|
|
|
|
data={"_st": "all",
|
|
|
|
"eml": MEMBERSHIPWORKS_USERNAME,
|
|
|
|
"org": "10000",
|
|
|
|
"pwd": MEMBERSHIPWORKS_PASSWORD})
|
|
|
|
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)
|
|
|
|
SFtoken = r.json()['SF']
|
|
|
|
|
|
|
|
# get list of member/staff IDs
|
|
|
|
r = requests.get(BASE_URL + "ylp",
|
|
|
|
params={"SF": SFtoken,
|
2018-08-07 18:33:12 -04:00
|
|
|
"lbl": ",".join([folder_map[f] for f in folders]),
|
2018-06-19 18:24:15 -04:00
|
|
|
"org": "15475", # unknown
|
|
|
|
"var": "_id,nam,ctc"})
|
|
|
|
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-09-18 14:02:34 -04:00
|
|
|
ids = [user['uid'] for user in r.json()['usr']]
|
2018-06-19 18:24:15 -04:00
|
|
|
|
|
|
|
# get members CSV
|
|
|
|
# TODO: maybe can just use previous get instead? would return JSON
|
|
|
|
r = requests.post(BASE_URL + "csv",
|
|
|
|
params={"SF": SFtoken},
|
|
|
|
data={"_rt": "946702800", # unknown
|
|
|
|
"mux": "", # unknown
|
|
|
|
"tid": ",".join(ids), # ids of members to get
|
|
|
|
"var": columns})
|
|
|
|
if r.status_code != 200:
|
|
|
|
print("MembershipWorks CSV Generation Error: ", r.status_code, r.reason)
|
|
|
|
print(r.text)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
return list(csv.DictReader(StringIO(r.text)))
|
|
|
|
|
2018-05-12 09:49:51 -04:00
|
|
|
def doImportRequest(ip, params=None, files=None):
|
|
|
|
"""Send a request to the door control import script"""
|
|
|
|
r = requests.post(
|
|
|
|
'https://' + ip + '/cgi-bin/import.cgi',
|
|
|
|
params=params,
|
|
|
|
files=files,
|
|
|
|
auth=requests.auth.HTTPDigestAuth(DOOR_USERNAME, DOOR_PASSWORD),
|
2018-06-10 22:55:13 -04:00
|
|
|
timeout=60,
|
2018-05-12 09:49:51 -04:00
|
|
|
verify=False) # ignore insecure SSL
|
|
|
|
xml = ET.XML(r.text)
|
|
|
|
if r.status_code != 200 \
|
|
|
|
or len(xml.findall("{http://www.hidglobal.com/VertX}Error")) > 0:
|
|
|
|
print("Door Updating Error: ", r.status_code, r.reason)
|
|
|
|
print(r.text)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
def doCSVImport(doorIP, csv):
|
|
|
|
"""Do the CSV import procedure on a door control"""
|
|
|
|
doImportRequest(doorIP, {"task": "importInit"})
|
|
|
|
doImportRequest(doorIP,
|
|
|
|
{"task": "importCardsPeople", "name": "cardspeopleschedule.csv"},
|
|
|
|
{"importCardsPeopleButton": ("cardspeopleschedule.csv", csv, 'text/csv')})
|
|
|
|
doImportRequest(doorIP, {"task": "importDone"})
|
2018-05-14 11:23:25 -04:00
|
|
|
|
|
|
|
def doXMLRequest(doorIP, xml, prefix=b'<?xml version="1.0" encoding="UTF-8"?>'):
|
|
|
|
r = requests.get(
|
|
|
|
'https://' + doorIP + '/cgi-bin/vertx_xml.cgi',
|
|
|
|
params={'XML': prefix + xml},
|
|
|
|
auth=requests.auth.HTTPDigestAuth(DOOR_USERNAME, DOOR_PASSWORD),
|
|
|
|
verify=False)
|
|
|
|
xml = ET.XML(r.text)
|
|
|
|
# probably meed to be more sane about this
|
|
|
|
if r.status_code != 200 \
|
|
|
|
or len(xml.findall("{http://www.hidglobal.com/VertX}Error")) > 0:
|
|
|
|
print("Door Updating Error: ", r.status_code, r.reason)
|
|
|
|
print(r.text)
|
|
|
|
sys.exit(1)
|
|
|
|
return xml
|