Refactor MembershipWorks handling into separate class/file
This commit is contained in:
parent
25532bf21b
commit
c52b76534c
82
MembershipWorks.py
Normal file
82
MembershipWorks.py
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import csv
|
||||||
|
from io import StringIO
|
||||||
|
import requests
|
||||||
|
|
||||||
|
BASE_URL = "https://api.membershipworks.com/v1/"
|
||||||
|
|
||||||
|
class MembershipWorksRemoteError(Exception):
|
||||||
|
def __init__(self, reason, r):
|
||||||
|
super().__init__(
|
||||||
|
f"Error when attempting {reason}: {r.status_code} {r.reason}\n{r.text}")
|
||||||
|
|
||||||
|
class MembershipWorks:
|
||||||
|
def __init__(self):
|
||||||
|
self.auth_token = None
|
||||||
|
self.org_num = None
|
||||||
|
|
||||||
|
def login(self, username, password):
|
||||||
|
"""Authenticate against the membershipworks api"""
|
||||||
|
r = requests.post(BASE_URL + 'usr',
|
||||||
|
data={"_st": "all",
|
||||||
|
"eml": username,
|
||||||
|
"org": "10000",
|
||||||
|
"pwd": password})
|
||||||
|
if r.status_code != 200 or 'SF' not in r.json():
|
||||||
|
raise MembershipWorksRemoteError('login', r)
|
||||||
|
self.auth_token = r.json()['SF']
|
||||||
|
self.org_num = r.json()['org']
|
||||||
|
|
||||||
|
def _inject_auth(self, kwargs):
|
||||||
|
# TODO: should probably be a decorator or something
|
||||||
|
if self.auth_token is None:
|
||||||
|
raise RuntimeError('Not Logged in to MembershipWorks')
|
||||||
|
# add auth token to params
|
||||||
|
if 'params' not in kwargs:
|
||||||
|
kwargs['params'] = {}
|
||||||
|
kwargs['params']["SF"] = self.auth_token
|
||||||
|
|
||||||
|
def _get(self, *args, **kwargs):
|
||||||
|
self._inject_auth(kwargs)
|
||||||
|
# TODO: should probably do some error handling in here
|
||||||
|
return requests.get(*args, **kwargs)
|
||||||
|
|
||||||
|
def _post(self, *args, **kwargs):
|
||||||
|
self._inject_auth(kwargs)
|
||||||
|
# TODO: should probably do some error handling in here
|
||||||
|
return requests.post(*args, **kwargs)
|
||||||
|
|
||||||
|
def get_member_ids(self, folders):
|
||||||
|
# TODO: this is hardcoded for CMS
|
||||||
|
folder_map = {
|
||||||
|
'members': '5ae37979f033bfe8534f8799',
|
||||||
|
'staff': '5771675edcdf126302a2f6b9',
|
||||||
|
'misc': '5b69ee9bf033bf8e7346c434'
|
||||||
|
}
|
||||||
|
|
||||||
|
r = self._get(BASE_URL + "ylp", params={
|
||||||
|
"lbl": ",".join([folder_map[f] for f in folders]),
|
||||||
|
"org": self.org_num,
|
||||||
|
"var": "_id,nam,ctc"})
|
||||||
|
if r.status_code != 200 or 'usr' not in r.json():
|
||||||
|
raise MembershipWorksRemoteError('user listing', r)
|
||||||
|
|
||||||
|
# get list of member/staff IDs
|
||||||
|
return [user['uid'] for user in r.json()['usr']]
|
||||||
|
|
||||||
|
def get_members(self, folders, columns):
|
||||||
|
""" Pull the members csv from the membershipworks api
|
||||||
|
folders: a list of the names of the folders to get
|
||||||
|
(see folder_map in this function for mapping to ids)
|
||||||
|
columns: which columns to get"""
|
||||||
|
ids = self.get_member_ids(folders)
|
||||||
|
|
||||||
|
# get members CSV
|
||||||
|
# TODO: maybe can just use previous get instead? would return JSON
|
||||||
|
r = self._post(BASE_URL + "csv",
|
||||||
|
data={"_rt": "946702800", # unknown
|
||||||
|
"mux": "", # unknown
|
||||||
|
"tid": ",".join(ids), # ids of members to get
|
||||||
|
"var": columns})
|
||||||
|
if r.status_code != 200:
|
||||||
|
raise MembershipWorksRemoteError('csv generation', r)
|
||||||
|
return list(csv.DictReader(StringIO(r.text)))
|
59
common.py
59
common.py
@ -1,15 +1,12 @@
|
|||||||
import csv
|
|
||||||
from ruamel.yaml import YAML
|
from ruamel.yaml import YAML
|
||||||
import urllib3
|
import urllib3
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
from io import StringIO
|
|
||||||
import requests
|
|
||||||
from hid.DoorController import DoorController
|
from hid.DoorController import DoorController
|
||||||
|
|
||||||
from passwords import (DOOR_USERNAME, DOOR_PASSWORD,
|
from passwords import DOOR_USERNAME, DOOR_PASSWORD
|
||||||
MEMBERSHIPWORKS_USERNAME, MEMBERSHIPWORKS_PASSWORD)
|
from passwords import MEMBERSHIPWORKS_USERNAME, MEMBERSHIPWORKS_PASSWORD
|
||||||
|
|
||||||
|
from MembershipWorks import MembershipWorks
|
||||||
# it's fine, ssl certs are for losers anyway
|
# it's fine, ssl certs are for losers anyway
|
||||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||||
|
|
||||||
@ -28,51 +25,5 @@ doors = {doorName: DoorController(doorData['ip'],
|
|||||||
memberLevels = config['memberLevels']
|
memberLevels = config['memberLevels']
|
||||||
doorSpecificSchedules = config['doorSpecificSchedules']
|
doorSpecificSchedules = config['doorSpecificSchedules']
|
||||||
|
|
||||||
def getMembershipworksData(folders, columns):
|
membershipworks = MembershipWorks()
|
||||||
""" Pull the members csv from the membershipworks api
|
membershipworks.login(MEMBERSHIPWORKS_USERNAME, MEMBERSHIPWORKS_PASSWORD)
|
||||||
folders: a list of the names of the folders to get
|
|
||||||
(see folder_map in this function for mapping to ids)
|
|
||||||
columns: which columns to get"""
|
|
||||||
BASE_URL = "https://api.membershipworks.com/v1/"
|
|
||||||
folder_map = {'members': '5ae37979f033bfe8534f8799',
|
|
||||||
'staff': '5771675edcdf126302a2f6b9',
|
|
||||||
'misc': '5b69ee9bf033bf8e7346c434'}
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
login_data = r.json()
|
|
||||||
|
|
||||||
# get list of member/staff IDs
|
|
||||||
r = requests.get(BASE_URL + "ylp",
|
|
||||||
params={"SF": login_data['SF'],
|
|
||||||
"lbl": ",".join([folder_map[f] for f in folders]),
|
|
||||||
"org": login_data['org'],
|
|
||||||
"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)
|
|
||||||
ids = [user['uid'] for user in r.json()['usr']]
|
|
||||||
|
|
||||||
# get members CSV
|
|
||||||
# TODO: maybe can just use previous get instead? would return JSON
|
|
||||||
r = requests.post(BASE_URL + "csv",
|
|
||||||
params={"SF": login_data['SF']},
|
|
||||||
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)))
|
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
from common import (doors, getMembershipworksData, memberLevels,
|
from common import doors, membershipworks, memberLevels, doorSpecificSchedules
|
||||||
doorSpecificSchedules)
|
|
||||||
from hid.Credential import Credential
|
from hid.Credential import Credential
|
||||||
from hid.DoorController import ROOT, E
|
from hid.DoorController import ROOT, E
|
||||||
|
|
||||||
|
|
||||||
class Member():
|
class Member():
|
||||||
def __init__(self, forename="", surname="", membershipWorksID="",
|
def __init__(self, forename="", surname="", membershipWorksID="",
|
||||||
middleName="", email="", phone="",
|
middleName="", email="", phone="",
|
||||||
@ -230,7 +228,7 @@ def update_door(door, members):
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
memberData = getMembershipworksData(
|
memberData = membershipworks.get_members(
|
||||||
['members', 'staff', 'misc'],
|
['members', 'staff', 'misc'],
|
||||||
"_id,nam,phn,eml,lvl,lbl,xws,xms,xsc,xas,xfd,xac,xcf,xeh,xse")
|
"_id,nam,phn,eml,lvl,lbl,xws,xms,xsc,xas,xfd,xac,xcf,xeh,xse")
|
||||||
|
|
||||||
|
@ -6,8 +6,7 @@ from flask import Flask, render_template, request
|
|||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
from common import *
|
from common import doors, membershipworks
|
||||||
from hid.DoorController import DoorController
|
|
||||||
|
|
||||||
def parse_list(member, regex):
|
def parse_list(member, regex):
|
||||||
data_list = []
|
data_list = []
|
||||||
@ -46,7 +45,7 @@ def main():
|
|||||||
return render_template("members.html",
|
return render_template("members.html",
|
||||||
error="Enter at least 3 characters to search")
|
error="Enter at least 3 characters to search")
|
||||||
|
|
||||||
data = getMembershipworksData(
|
data = membershipworks.get_members(
|
||||||
['members', 'staff'],
|
['members', 'staff'],
|
||||||
"lvl,xws,xms,xsc,xas,xfd,xac,phn,eml,lbl,xcf,nam,end")
|
"lvl,xws,xms,xsc,xas,xfd,xac,phn,eml,lbl,xcf,nam,end")
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import re
|
|||||||
import string
|
import string
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from common import getMembershipworksData
|
from common import membershipworks
|
||||||
|
|
||||||
LDAP_BASE = "cn=users,dc=sawtooth,dc=claremontmakerspace,dc=org"
|
LDAP_BASE = "cn=users,dc=sawtooth,dc=claremontmakerspace,dc=org"
|
||||||
GROUP_BASE = "cn=groups,dc=sawtooth,dc=claremontmakerspace,dc=org"
|
GROUP_BASE = "cn=groups,dc=sawtooth,dc=claremontmakerspace,dc=org"
|
||||||
@ -32,7 +32,7 @@ def makeAppendGroups(member):
|
|||||||
for group in groups], [])
|
for group in groups], [])
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
members = getMembershipworksData(['members', 'staff'],
|
members = membershipworks.get_members(['members', 'staff'],
|
||||||
"lvl,phn,eml,lbl,nam,end,_id")
|
"lvl,phn,eml,lbl,nam,end,_id")
|
||||||
makeGroups(members)
|
makeGroups(members)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user