From dfb01060ccf4c47b7224c5018f366bca3a5b652d Mon Sep 17 00:00:00 2001 From: Maff Date: Thu, 16 May 2019 02:13:49 +0100 Subject: [PATCH] added some base abstraction classes for easier implementation of further apis, added demo script --- Py3CX/__init__.py | 63 +++++++++++++++++++++++++++++++++++++++++------ demo.py | 10 ++++++++ 2 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 demo.py diff --git a/Py3CX/__init__.py b/Py3CX/__init__.py index bb8d0a8..806e9e2 100644 --- a/Py3CX/__init__.py +++ b/Py3CX/__init__.py @@ -12,13 +12,15 @@ class Request: from requests import ConnectionError, exceptions def __init__(self, uri, verify): from requests import Session + self.uri=uri self.base="%s/api/{}" % uri + self.last=None self.sess=Session() self.sess.verify=verify def get(self, api, params=None, expect=200): try: - resp=self.sess.get(url=self.base.format(api), params=params) + self.last=resp=self.sess.get(url=self.base.format(api), params=params) assert (resp.status_code==expect) except AssertionError: raise APIError("Assertion error when handling API response; response code was %s, but expected response was %s" % (resp.status_code, expect)) @@ -32,7 +34,7 @@ class Request: def post(self, api, params, expect=200): try: - resp=self.sess.post(url=self.base.format(api), json=params) + self.last=resp=self.sess.post(url=self.base.format(api), json=params) assert (resp.status_code==expect) except AssertionError: raise APIError("Assertion error when handling API response; response code was %s, but expected response was %s" % (resp.status_code, expect)) @@ -46,14 +48,59 @@ class Request: raise APIError("Other exception raised during API call: %s" % str(e)) return resp -class Extension(object): - def __init__(self, parent, params): +class ReadOnlyObject(object): + def __init__(self, parent, api): self.tcx=parent + self.api=api + def refresh(self, params={}): + self._result=self.tcx.rq.get(self.api, params=params) + self.active=self._result.json() +class TransactionalObject(object): + def __init__(self, parent, api, submit='edit/save', discard='edit/cancel'): + self.tcx=parent + self.api=api + self.submit=submit + self.discard=discard + def create(self, params): + self._result=self.tcx.rq.post(self.api, params=params) + self._session=self._result.json()['Id'] + self.active=self._result.json()['ActiveObject'] + def submit(self, params): + raise ValidationError("NotImplemented error") + def cancel(self): + self.tcx.rq.post(self.discard, params={ + 'Id':self._session}) + +class User(TransactionalObject): + def __init__(self, parent, params): + super().__init__(parent, 'ExtensionList/set') self.params=params self.load() - def load(self): - res=self.tcx.rq.get('ExtensionList') + self.create(params={ + 'Id':self.params}) + parms=self.active + self.id=parms['Id'] + self.enabled=not parms['Disabled']['_value'] + self.sip_id=parms['SIPId']['_value'] + #RecordCallsOption - enum + self.callrecs=parms['RecordCalls']['selected'] + self.sip_host=parms['MyPhoneLocalInterface']['selected'] + self.sip_host_addrs=parms['MyPhoneLocalInterface']['possibleValues'] + self.sip_authid=parms['AuthId']['_value'] + self.sip_authpw=parms['AuthPassword']['_value'] + self.provision_uri=parms['MyPhoneProvLink']['_value'] + self.webpw=parms['AccessPassword']['_value'] + self.extension=Extension(self.tcx, self.params) + self.cancel() +class Extension(ReadOnlyObject): + def __init__(self, parent, params): + super().__init__(parent, api='ExtensionList') + self.params=params + self.load() + def load(self): + self.refresh(params=self.params) + res=self._result self.timestamp=res.headers.get('date') res=list(filter(lambda ext: ext['Number'] == self.params, res.json()['list'])) assert (len(res)>0), "No extension found for: %s" % self.params @@ -70,7 +117,6 @@ class Extension(object): self.mobile=res['MobileNumber'] self.online=res['IsRegistered'] - class Py3CX: def __init__(self, uri=None, tls_verify=True): from os import getenv @@ -85,9 +131,10 @@ class Py3CX: self.uname=username self.passw=password assert (self.uname is not None and self.passw is not None), "Authentication information needed" - self.rq.post('login', params={ + rs=self.rq.post('login', params={ 'Username': self.uname, 'Password': self.passw}) + self.rq.sess.headers.update({'x-xsrf-token':rs.cookies['XSRF-TOKEN']}) @property def authenticated(self): diff --git a/demo.py b/demo.py new file mode 100644 index 0000000..d4da9cf --- /dev/null +++ b/demo.py @@ -0,0 +1,10 @@ +site='https://mysite.3cx.com' +user='123' +pwrd='AbCd123Ef' +import Py3CX +tcx=Py3CX.Py3CX(uri=site) +print("Am I logged in? %s" % tcx.authenticated) +tcx.authenticate(username=user, password=pwrd) +print("Am I logged in now? %s" % tcx.authenticated) +me=Py3CX.User('101') +friend=Py3CX.User('116') \ No newline at end of file