Refactor MembershipWorks handling into separate class/file

This commit is contained in:
Adam Goldsmith 2020-02-06 17:48:09 -05:00
parent 25532bf21b
commit c52b76534c
5 changed files with 93 additions and 63 deletions

82
MembershipWorks.py Normal file
View 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)))

View File

@ -1,15 +1,12 @@
import csv
from ruamel.yaml import YAML
import urllib3
import os
import sys
from io import StringIO
import requests
from hid.DoorController import DoorController
from passwords import (DOOR_USERNAME, DOOR_PASSWORD,
MEMBERSHIPWORKS_USERNAME, MEMBERSHIPWORKS_PASSWORD)
from passwords import DOOR_USERNAME, DOOR_PASSWORD
from passwords import MEMBERSHIPWORKS_USERNAME, MEMBERSHIPWORKS_PASSWORD
from MembershipWorks import MembershipWorks
# it's fine, ssl certs are for losers anyway
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
@ -28,51 +25,5 @@ doors = {doorName: DoorController(doorData['ip'],
memberLevels = config['memberLevels']
doorSpecificSchedules = config['doorSpecificSchedules']
def getMembershipworksData(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"""
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)))
membershipworks = MembershipWorks()
membershipworks.login(MEMBERSHIPWORKS_USERNAME, MEMBERSHIPWORKS_PASSWORD)

View File

@ -1,11 +1,9 @@
#!/usr/bin/env python3
from common import (doors, getMembershipworksData, memberLevels,
doorSpecificSchedules)
from common import doors, membershipworks, memberLevels, doorSpecificSchedules
from hid.Credential import Credential
from hid.DoorController import ROOT, E
class Member():
def __init__(self, forename="", surname="", membershipWorksID="",
middleName="", email="", phone="",
@ -230,7 +228,7 @@ def update_door(door, members):
def main():
memberData = getMembershipworksData(
memberData = membershipworks.get_members(
['members', 'staff', 'misc'],
"_id,nam,phn,eml,lvl,lbl,xws,xms,xsc,xas,xfd,xac,xcf,xeh,xse")

View File

@ -6,8 +6,7 @@ from flask import Flask, render_template, request
app = Flask(__name__)
from common import *
from hid.DoorController import DoorController
from common import doors, membershipworks
def parse_list(member, regex):
data_list = []
@ -46,7 +45,7 @@ def main():
return render_template("members.html",
error="Enter at least 3 characters to search")
data = getMembershipworksData(
data = membershipworks.get_members(
['members', 'staff'],
"lvl,xws,xms,xsc,xas,xfd,xac,phn,eml,lbl,xcf,nam,end")

View File

@ -4,7 +4,7 @@ import re
import string
import subprocess
from common import getMembershipworksData
from common import membershipworks
LDAP_BASE = "cn=users,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], [])
def main():
members = getMembershipworksData(['members', 'staff'],
members = membershipworks.get_members(['members', 'staff'],
"lvl,phn,eml,lbl,nam,end,_id")
makeGroups(members)