def get_members(self, group_id): """ Returns a list of restclients.GroupMember objects for the group identified by the passed group ID. """ if not self._is_valid_group_id(group_id): raise InvalidGroupID(group_id) dao = GWS_DAO() url = "/group_sws/v2/group/%s/member" % group_id response = dao.getURL(url, self._headers({"Accept": "text/xhtml"})) if response.status != 200: raise DataFailureException(url, response.status, response.data) return self._members_from_xhtml(response.data)
def get_resource(url, subdomain): """ Issue a GET request to IASystem with the given url and return a response in Collection+json format. :returns: http response with content in json """ headers = {"Accept": "application/vnd.collection+json"} timer = Timer() response = IASYSTEM_DAO().getURL(url, headers, subdomain) log_info(logger, "%s ==status==> %s" % (url, response.status), timer) if response.status != 200: logger.debug("%s ==data==> %s" % (url, response.data)) raise DataFailureException(url, response.status, response.data) return json.loads(response.data)
def put_name_by_netid(self, netid, data): """ Updates display info for a Name object """ if not self.valid_uwnetid(netid): raise InvalidNetID(netid) pd = self.valid_irws_name_from_json(data) dao = IRWS_DAO() url = "/%s/v1/name/uwnetid=%s" % (self._service_name, netid.lower()) response = dao.putURL(url, {"Accept": "application/json"}, json.dumps(pd)) if response.status != 200: raise DataFailureException(url, response.status, response.data) return response.status
def import_str(self, csv, params={}): """ Imports a CSV string. https://canvas.instructure.com/doc/api/sis_imports.html#method.sis_imports_api.create """ params["import_type"] = SISImportModel.CSV_IMPORT_TYPE url = "/api/v1/accounts/%s/sis_imports.json%s" % ( settings.RESTCLIENTS_CANVAS_ACCOUNT_ID, self._params(params)) headers = {"Accept": "application/json", "Content-Type": "text/csv"} response = Canvas_DAO().postURL(url, headers, csv) if not (response.status == 200 or response.status == 204): raise DataFailureException(url, response.status, response.data) return self._sis_import_from_json(json.loads(response.data))
def get_person_by_netid(self, netid): """ Returns a restclients.Person object for the given netid. If the netid isn't found, or if there is an error communicating with the PWS, a DataFailureException will be thrown. """ if not self.valid_uwnetid(netid): raise InvalidNetID(netid) dao = PWS_DAO() url = "%s/%s/full.json" % (PERSON_PREFIX, netid.lower()) response = dao.getURL(url, {"Accept": "application/json"}) if response.status != 200: raise DataFailureException(url, response.status, response.data) return self._person_from_json(response.data)
def get_channel_by_surrogate_id(self, channel_type, surrogate_id): """ Get a channel by surrogate id """ key = "%s|%s" % (channel_type, surrogate_id) url = "/notification/v1/channel/%s" % (quote(key)) dao = NWS_DAO() response = dao.getURL(url, {"Accept": "application/json"}) if response.status != 200: raise DataFailureException(url, response.status, response.data) channel = Channel() Serializer().deserialize(channel, response.data) return channel
def get_entity_by_regid(self, regid): """ Returns a restclients.Entity object for the given regid. If the regid isn't found, or if there is an error communicating with the PWS, a DataFailureException will be thrown. """ if not self.valid_uwregid(regid): raise InvalidRegID(regid) dao = PWS_DAO() url = "%s/%s.json" % (ENTITY_PREFIX, regid.upper()) response = dao.getURL(url, {"Accept": "application/json"}) if response.status != 200: raise DataFailureException(url, response.status, response.data) return self._entity_from_json(response.data)
def get_name_by_netid(self, netid): """ Returns a restclients.irws.Name object for the given netid. If the netid isn't found, nothing will be returned. If there is an error communicating with the IRWS, a DataFailureException will be thrown. """ if not self.valid_uwnetid(netid): raise InvalidNetID(netid) dao = IRWS_DAO() url = "/%s/v1/name/uwnetid=%s" % (self._service_name, netid.lower()) response = dao.getURL(url, {"Accept": "application/json"}) if response.status != 200: raise DataFailureException(url, response.status, response.data) return self._name_from_json(response.data)
def get_contact(self, regid): """ Returns data for the given regid. """ if not self.valid_uwregid(regid): raise InvalidRegID(regid) dao = PWS_DAO() url = "%s/%s/full.json" % (PERSON_PREFIX, regid.upper()) response = dao.getURL(url, {"Accept": "application/json"}) if response.status == 404: return if response.status != 200: raise DataFailureException(url, response.status, response.data) return json.loads(response.data)
def _get_report_file(self, url): # Ensure file url matches the hostname in settings, # workaround for Canvas bug help.instructure.com/tickets/362386 url = re.sub(r'^https://[^/]+', settings.RESTCLIENTS_CANVAS_HOST, url) timeout = getattr(settings, "RESTCLIENTS_TIMEOUT", 15.0) cafile = getattr(settings, "RESTCLIENTS_CA_BUNDLE", "/etc/ssl/certs/ca-bundle.crt") pool_manager = PoolManager(cert_reqs="CERT_REQUIRED", ca_certs=cafile, timeout=timeout, retries=5) response = pool_manager.request("GET", url) if response.status != 200: raise DataFailureException(url, response.status, response.data) return response.data
def update_channel(self, channel): """ Update an existing channel :param channel: is the updated channel that the client wants to update """ #Update the channel dao = NWS_DAO() url = "/notification/v1/channel/%s" % (channel.channel_id) put_response = dao.putURL(url, {"Content-Type": "application/json"}, Serializer().serialize(channel)) #Http response code 204 No Content: #The server has fulfilled the request but does not need to return an entity-body if put_response.status != 204: raise DataFailureException(url, put_response.status, put_response.data) return put_response.status
def create_group(self, group): """ Creates a group from the passed restclients.Group object. """ body = self._xhtml_from_group(group) dao = GWS_DAO() url = "/group_sws/v2/group/%s" % group.name response = dao.putURL( url, self._headers({ "Accept": "text/xhtml", "Content-Type": "text/xhtml" }), body) if response.status != 201: raise DataFailureException(url, response.status, response.data) return self._group_from_xhtml(response.data)
def create_new_channel(self, channel): """ Create a new channel :param channel: is the new channel that the client wants to create """ #Create new channel dao = NWS_DAO() url = "/notification/v1/channel" post_response = dao.postURL(url, {"Content-Type": "application/json"}, Serializer().serialize(channel)) #HTTP Status Code 201 Created: The request has been fulfilled and resulted #in a new resource being created if post_response.status != 201: raise DataFailureException(url, post_response.status, post_response.data) return post_response.status
def get_channel_by_channel_id(self, channel_id): """ Get a channel by channel id """ #Validate the channel_id self._validate_uuid(channel_id) url = "/notification/v1/channel/%s" % (channel_id) dao = NWS_DAO() response = dao.getURL(url, {"Accept": "application/json"}) if response.status != 200: raise DataFailureException(url, response.status, response.data) channel = Channel() Serializer().deserialize(channel, response.data) return channel
def get_effective_member_count(self, group_id): """ Returns a count of effective members for the group identified by the passed group ID. """ if not self._is_valid_group_id(group_id): raise InvalidGroupID(group_id) dao = GWS_DAO() url = "/group_sws/v2/group/%s/effective_member?view=count" % group_id response = dao.getURL(url, self._headers({"Accept": "text/xhtml"})) if response.status != 200: raise DataFailureException(url, response.status, response.data) root = etree.fromstring(response.data) count = root.find('.//*[@class="member_count"]').get("count") return int(count)
def get_endpoints_by_subscriber_id(self, subscriber_id): """ Search for all endpoints by a given subscriber """ #Validate input self._validate_subscriber_id(subscriber_id) url = "/notification/v1/endpoint?subscriber_id=%s" % (subscriber_id) dao = NWS_DAO() response = dao.getURL(url, {"Accept": "application/json"}) if response.status != 200: raise DataFailureException(url, response.status, response.data) endpoint_list = EndpointList() Serializer().deserialize(endpoint_list, response.data) return endpoint_list.view_models
def get_endpoint_by_endpoint_id(self, endpoint_id): """ Get an endpoint by endpoint id """ #Validate the channel_id self._validate_uuid(endpoint_id) url = "/notification/v1/endpoint/%s" % (endpoint_id) dao = NWS_DAO() response = dao.getURL(url, {"Accept": "application/json"}) if response.status != 200: raise DataFailureException(url, response.status, response.data) endpoint = Endpoint() Serializer().deserialize(endpoint, response.data) return endpoint
def get_verba_link_for_schedule(self, schedule): """ Returns a link to verba. The link varies by campus and schedule. Multiple calls to this with the same schedule may result in different urls. """ dao = Book_DAO() url = self.get_verba_url(schedule) response = dao.getURL(url, {"Accept": "application/json"}) if response.status != 200: raise DataFailureException(url, response.status, response.data) data = json.loads(response.data) for key in data: if re.match(r'^[A-Z]{2}[0-9]{5}$', key): return "%s%s&quarter=%s" % (BOOK_PREFIX, key, schedule.term.quarter)
def get_graderoster(section, instructor): """ Returns a restclients.GradeRoster for the passed Section model and instructor Person. """ label = GradeRoster(section=section, instructor=instructor).graderoster_label() url = "%s/%s" % (graderoster_url, encode_section_label(label)) headers = {"Accept": "text/xhtml", "Connection": "keep-alive", "X-UW-Act-as": instructor.uwnetid} response = SWS_DAO().getURL(url, headers) if response.status != 200: root = etree.fromstring(response.data) msg = root.find(".//*[@class='status_description']").text.strip() raise DataFailureException(url, response.status, msg) return graderoster_from_xhtml(response.data, section, instructor)
def is_effective_member(self, group_id, netid): """ Returns True if the netid is in the group, False otherwise. """ if not self._is_valid_group_id(group_id): raise InvalidGroupID(group_id) # GWS doesn't accept EPPNs on effective member checks, for UW users netid = re.sub('@washington.edu', '', netid) dao = GWS_DAO() url = "/group_sws/v2/group/%s/effective_member/%s" % (group_id, netid) response = dao.getURL(url, self._headers({"Accept": "text/xhtml"})) if response.status == 404: return False elif response.status == 200: return True else: raise DataFailureException(url, response.status, response.data)
def create_new_message(self, dispatch): """ Create a new dispatch :param dispatch: is the new dispatch that the client wants to create """ #Create new dispatch dao = NWS_DAO() url = "/notification/v1/dispatch" data = Serializer().serialize(dispatch) post_response = dao.postURL(url, {"Content-Type": "application/json"}, data) if post_response.status != 200: raise DataFailureException(url, post_response.status, post_response.data) return post_response.status
def post_hr_person_by_netid(self, netid, data): """ Post to the irws person hr resource. We look up the person by netid to get the uri to post to. """ if not self.valid_uwnetid(netid): raise InvalidNetID(netid) hepps_person = self.valid_hr_person_from_json(data) identity = self.get_identity_by_netid(netid) if not {'hepps', 'uwhr'} & set(identity.identifiers.keys()): raise IRWSPersonNotFound( 'netid {} not a hepps/uwhr person'.format(netid)) source = 'uwhr' if 'uwhr' in identity.identifiers.keys() else 'hepps' post_url = '/{}/v1{}'.format(self._service_name, identity.identifiers[source]) response = IRWS_DAO().postURL(post_url, {'Accept': 'application/json'}, json.dumps(hepps_person)) if response.status != 200: raise DataFailureException(post_url, response.status, response.data) return response.status
def update_members(self, group_id, members): """ Updates the membership of the group represented by the passed group id. Returns a list of members not found. """ if not self._is_valid_group_id(group_id): raise InvalidGroupID(group_id) body = self._xhtml_from_members(group_id, members) dao = GWS_DAO() url = "/group_sws/v2/group/%s/member" % group_id response = dao.putURL( url, self._headers({ "Content-Type": "text/xhtml", "If-Match": "*" }), body) if response.status != 200: raise DataFailureException(url, response.status, response.data) return self._notfoundmembers_from_xhtml(response.data)
def update_graderoster(graderoster): """ Updates the graderoster resource for the passed restclients.GradeRoster model. A new restclients.GradeRoster is returned, representing the document returned from the update request. """ label = graderoster.graderoster_label() url = "%s/%s" % (graderoster_url, encode_section_label(label)) headers = {"Content-Type": "application/xhtml+xml", "Connection": "keep-alive", "X-UW-Act-as": graderoster.instructor.uwnetid} body = graderoster.xhtml() response = SWS_DAO().putURL(url, headers, body) if response.status != 200: root = etree.fromstring(response.data) msg = root.find(".//*[@class='status_description']").text.strip() raise DataFailureException(url, response.status, msg) return graderoster_from_xhtml(response.data, graderoster.section, graderoster.instructor)
def get_resource(url): timer = Timer() dao = DigitLib_DAO() response = dao.getURL(url, {}) log_info(logger, "%s ==status==> %s" % (url, response.status), timer) if response.status == 302: logger.debug("%s ==headers==> %s" % (url, response.headers)) return response.headers if response.status == 200 and response.data is not None: logger.debug("%s ==data==> %s" % (url, response.data)) return json.loads(response.data) raise DataFailureException(url, response.status, response.data)
def delete_channel(self, channel_id): """ Deleting an existing channel :param channel_id: is the channel that the client wants to delete """ #Validate the subscription_id self._validate_uuid(channel_id) #Delete the subscription url = "/notification/v1/channel/%s" % (channel_id) dao = NWS_DAO() delete_response = dao.deleteURL(url, None) #Http response code 204 No Content: #The server has fulfilled the request but does not need to return an entity-body if delete_response.status != 204: raise DataFailureException(url, delete_response.status, delete_response.data) return delete_response.status
def update_person(self, person): """ Update an existing person :param person: is the updated person that the client wants to update """ #Validate self._validate_regid(person.person_id) self._validate_subscriber_id(person.surrogate_id) attributes = person.get_attributes() person.attributes = None for attribute in attributes: if attribute.name in MANAGED_ATTRIBUTES: continue person.add_attribute(attribute.name, attribute.value, None, None) # ATTRIBUTE_TYPE_EMAIL_DISPATCHED_COUNT = 'DispatchedEmailCount' # ATTRIBUTE_TYPE_SMS_DISPATCHED_COUNT = 'DispatchedTextMessageCount' # ATTRIBUTE_TYPE_SMS_SENT_COUNT = 'SentTextMessageCount' # ATTRIBUTE_TYPE_SUBSCRIPTION_COUNT = 'SubscriptionCount' dao = NWS_DAO() url = "/notification/v1/person/%s" % (person.person_id) headers = {"Content-Type": "application/json"} if self.override_user is not None: headers['X_UW_ACT_AS'] = self.override_user put_response = dao.putURL(url, headers, Serializer().serialize(person)) #Http response code 204 No Content: #The server has fulfilled the request but does not need to return an entity-body if put_response.status != 204: raise DataFailureException(url, put_response.status, put_response.data) return put_response.status
def _get_resource_url(self, url, auto_page, data_key): """ Canvas GET method on a full url. Return representation of the requested resource, chasing pagination links to coalesce resources if indicated. """ response = Canvas_DAO().getURL(url, {"Accept": "application/json"}) if response.status != 200: raise DataFailureException(url, response.status, response.data) data = json.loads(response.data) self.next_page_url = self._next_page(response) if auto_page and self.next_page_url: if isinstance(data, list): data.extend( self._get_resource_url(self.next_page_url, True, data_key)) elif isinstance(data, dict) and data_key is not None: data[data_key].extend( self._get_resource_url(self.next_page_url, True, data_key)[data_key]) return data
def get_books_by_quarter_sln(self, quarter, sln): dao = Book_DAO() sln_string = self._get_sln_string(sln) url = "/myuw/myuw_mobile_beta.ubs?quarter=%s&%s" % ( quarter, sln_string, ) response = dao.getURL(url, {"Accept": "application/json"}) if response.status != 200: raise DataFailureException(url, response.status, response.data) data = json.loads(response.data) books = [] sln_data = data[str(sln)] if len(sln_data) > 0: for book_data in sln_data: book = Book() book.isbn = book_data["isbn"] book.title = book_data["title"] book.price = book_data["price"] book.used_price = book_data["used_price"] book.is_required = book_data["required"] book.notes = book_data["notes"] book.cover_image_url = book_data["cover_image"] book.authors = [] for author_data in book_data["authors"]: author = BookAuthor() author.name = author_data["name"] book.authors.append(author) books.append(book) return books
def create_new_subscription(self, subscription): """ Create a new subscription :param subscription: is the new subscription that the client wants to create """ #Validate input if subscription.get_subscription_id() is not None: self._validate_uuid(subscription.get_subscription_id()) if subscription.get_endpoint() is not None: if subscription.get_endpoint().user: self._validate_subscriber_id(subscription.endpoint.user) if subscription.get_endpoint().get_endpoint_id() is not None: self._validate_uuid(subscription.endpoint.get_endpoint_id()) if subscription.get_channel() is not None: self._validate_uuid(subscription.channel.get_channel_id()) #Create new subscription dao = NWS_DAO() url = "/notification/v1/subscription" headers = {"Content-Type": "application/json"} if self.override_user is not None: headers['X_UW_ACT_AS'] = self.override_user post_response = dao.postURL(url, headers, Serializer().serialize(subscription)) #HTTP Status Code 201 Created: The request has been fulfilled and resulted #in a new resource being created if post_response.status != 201: raise DataFailureException(url, post_response.status, post_response.data) return post_response.status