Update MembershipWorks module to v2 of the API, where available
still stuck using the v1 csv endpoint, haven't found an easy alternative and it hasn't been changed yet for their v2
This commit is contained in:
parent
cfccc433dd
commit
3849aca918
@ -3,7 +3,7 @@ from io import StringIO
|
|||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
BASE_URL = "https://api.membershipworks.com/v1/"
|
BASE_URL = "https://api.membershipworks.com"
|
||||||
|
|
||||||
# extracted from `SF._is.crm` in https://cdn.membershipworks.com/all.js
|
# extracted from `SF._is.crm` in https://cdn.membershipworks.com/all.js
|
||||||
CRM = {
|
CRM = {
|
||||||
@ -72,21 +72,30 @@ class MembershipWorksRemoteError(Exception):
|
|||||||
|
|
||||||
class MembershipWorks:
|
class MembershipWorks:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self.sess = requests.Session()
|
||||||
self.org_info = None
|
self.org_info = None
|
||||||
self.auth_token = None
|
self.auth_token = None
|
||||||
self.org_num = None
|
self.org_num = None
|
||||||
|
|
||||||
def login(self, username, password):
|
def login(self, username, password):
|
||||||
"""Authenticate against the membershipworks api"""
|
"""Authenticate against the membershipworks api"""
|
||||||
r = requests.post(
|
r = self.sess.post(
|
||||||
BASE_URL + "usr",
|
BASE_URL + "/v2/account/session",
|
||||||
data={"_st": "all", "eml": username, "org": "10000", "pwd": password},
|
data={"eml": username, "pwd": password},
|
||||||
|
headers={"X-Org": "10000"},
|
||||||
)
|
)
|
||||||
if r.status_code != 200 or "SF" not in r.json():
|
if r.status_code != 200 or "SF" not in r.json():
|
||||||
raise MembershipWorksRemoteError("login", r)
|
raise MembershipWorksRemoteError("login", r)
|
||||||
self.org_info = r.json()
|
self.org_info = r.json()
|
||||||
self.auth_token = self.org_info["SF"]
|
self.auth_token = self.org_info["SF"]
|
||||||
self.org_num = self.org_info["org"]
|
self.org_num = self.org_info["org"]
|
||||||
|
self.sess.headers.update(
|
||||||
|
{
|
||||||
|
"X-Org": str(self.org_num),
|
||||||
|
"X-Role": "admin",
|
||||||
|
"Authorization": "Bearer " + self.auth_token,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
def _inject_auth(self, kwargs):
|
def _inject_auth(self, kwargs):
|
||||||
# TODO: should probably be a decorator or something
|
# TODO: should probably be a decorator or something
|
||||||
@ -97,12 +106,12 @@ class MembershipWorks:
|
|||||||
kwargs["params"] = {}
|
kwargs["params"] = {}
|
||||||
kwargs["params"]["SF"] = self.auth_token
|
kwargs["params"]["SF"] = self.auth_token
|
||||||
|
|
||||||
def _get(self, *args, **kwargs):
|
def _get_v1(self, *args, **kwargs):
|
||||||
self._inject_auth(kwargs)
|
self._inject_auth(kwargs)
|
||||||
# TODO: should probably do some error handling in here
|
# TODO: should probably do some error handling in here
|
||||||
return requests.get(*args, **kwargs)
|
return requests.get(*args, **kwargs)
|
||||||
|
|
||||||
def _post(self, *args, **kwargs):
|
def _post_v1(self, *args, **kwargs):
|
||||||
self._inject_auth(kwargs)
|
self._inject_auth(kwargs)
|
||||||
# TODO: should probably do some error handling in here
|
# TODO: should probably do some error handling in here
|
||||||
return requests.post(*args, **kwargs)
|
return requests.post(*args, **kwargs)
|
||||||
@ -141,32 +150,30 @@ class MembershipWorks:
|
|||||||
for dek in self.org_info["dek"]:
|
for dek in self.org_info["dek"]:
|
||||||
# TODO: there must be a better way. this is stupid
|
# TODO: there must be a better way. this is stupid
|
||||||
if dek["dek"] == 1:
|
if dek["dek"] == 1:
|
||||||
ret["folders"][dek["lbl"]] = dek["_id"]
|
ret["folders"][dek["lbl"]] = dek["did"]
|
||||||
elif "cur" in dek:
|
elif "cur" in dek:
|
||||||
ret["levels"][dek["lbl"]] = dek["_id"]
|
ret["levels"][dek["lbl"]] = dek["did"]
|
||||||
elif "mux" in dek:
|
elif "mux" in dek:
|
||||||
ret["addons"][dek["lbl"]] = dek["_id"]
|
ret["addons"][dek["lbl"]] = dek["did"]
|
||||||
else:
|
else:
|
||||||
ret["labels"][dek["lbl"]] = dek["_id"]
|
ret["labels"][dek["lbl"]] = dek["did"]
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def get_member_ids(self, folders):
|
def get_member_ids(self, folders):
|
||||||
folder_map = self._parse_flags()["folders"]
|
folder_map = self._parse_flags()["folders"]
|
||||||
|
|
||||||
r = self._get(
|
r = self.sess.get(
|
||||||
BASE_URL + "ylp",
|
BASE_URL + "/v2/accounts",
|
||||||
params={
|
params={"dek": ",".join([folder_map[f] for f in folders])},
|
||||||
"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():
|
if r.status_code != 200 or "usr" not in r.json():
|
||||||
raise MembershipWorksRemoteError("user listing", r)
|
raise MembershipWorksRemoteError("user listing", r)
|
||||||
|
|
||||||
# get list of member ID matching the search
|
# get list of member ID matching the search
|
||||||
return [user["uid"] for user in r.json()["usr"]]
|
# dedup with set() to work around people with alt uids
|
||||||
|
# TODO: figure out why people have alt uids
|
||||||
|
return set(user["uid"] for user in r.json()["usr"])
|
||||||
|
|
||||||
# TODO: has issues with aliasing header names:
|
# TODO: has issues with aliasing header names:
|
||||||
# ex: "Personal Studio Space" Label vs Membership Addon/Field
|
# ex: "Personal Studio Space" Label vs Membership Addon/Field
|
||||||
@ -179,8 +186,8 @@ class MembershipWorks:
|
|||||||
|
|
||||||
# get members CSV
|
# get members CSV
|
||||||
# TODO: maybe can just use previous get instead? would return JSON
|
# TODO: maybe can just use previous get instead? would return JSON
|
||||||
r = self._post(
|
r = self._post_v1(
|
||||||
BASE_URL + "csv",
|
BASE_URL + "/v1/csv",
|
||||||
data={
|
data={
|
||||||
"_rt": "946702800", # unknown
|
"_rt": "946702800", # unknown
|
||||||
"mux": "", # unknown
|
"mux": "", # unknown
|
||||||
@ -200,8 +207,8 @@ class MembershipWorks:
|
|||||||
json gets a different version of the transactions list,
|
json gets a different version of the transactions list,
|
||||||
which contains a different set information
|
which contains a different set information
|
||||||
"""
|
"""
|
||||||
r = self._get(
|
r = self._get_v1(
|
||||||
BASE_URL + "csv",
|
BASE_URL + "/v1/csv",
|
||||||
params={
|
params={
|
||||||
"crm": "12,13,14,18,19", # transaction types, see CRM
|
"crm": "12,13,14,18,19", # transaction types, see CRM
|
||||||
**({"txl": ""} if json else {}),
|
**({"txl": ""} if json else {}),
|
||||||
|
Reference in New Issue
Block a user