def call_api(self, token): """ Get the user info from the API @param token: the current access token @return: user info (dict) """ req = urllib2.Request(url=self.userinfo_url) req.add_header("Authorization", "Bearer %s" % token) req.add_header("Accept", "application/json") userinfo = None try: f = urlopen(req) except HTTPError as e: message = "HTTP %s: %s" % (e.code, e.reason) current.log.error(message) else: try: userinfo = json.load(f) except ValueError as e: import sys message = sys.exc_info()[1] current.log.error(message) return userinfo
def parse_rss_2_cap(message): """ Parse RSS Feeds into the CAP Module """ db = current.db s3db = current.s3db table = s3db.msg_rss message_id = message.message_id record = db(table.message_id == message_id).select( table.id, table.channel_id, table.title, table.from_address, table.body, table.date, table.location_id, table.author, limitby=(0, 1)).first() if not record: return pstable = s3db.msg_parsing_status # not adding (pstable.channel_id == record.channel_id) to query # because two channels (http://host.domain/eden/cap/public.rss and # (http://host.domain/eden/cap/alert.rss) may contain common url # eg. http://host.domain/eden/cap/public/xx.cap pquery = (pstable.message_id == message_id) prows = db(pquery).select(pstable.id, pstable.is_parsed) for prow in prows: if prow.is_parsed: return alert_table = s3db.cap_alert info_table = s3db.cap_info # Is this an Update or a Create? # @ToDo: Use guid? # Use Body body = record.body or record.title query = (info_table.description == body) exists = db(query).select(info_table.id, limitby=(0, 1)).first() author = record.author if author: ptable = s3db.pr_person # https://code.google.com/p/python-nameparser/ from nameparser import HumanName name = HumanName(author) first_name = name.first middle_name = name.middle last_name = name.last query = (ptable.first_name == first_name) & \ (ptable.middle_name == middle_name) & \ (ptable.last_name == last_name) pexists = db(query).select(ptable.id, limitby=(0, 1)).first() if pexists: person_id = pexists.id else: person_id = ptable.insert(first_name=first_name, middle_name=middle_name, last_name=last_name) s3db.update_super(ptable, {"id": person_id}) else: person_id = None if exists: # @ToDo: Use XSLT info_id = exists.id db(info_table.id == info_id).update( headline=record.title, description=body, created_on=record.date, #location_id = record.location_id, #person_id = person_id, ) else: # Embedded link url = record.from_address import_xml = s3db.resource("cap_alert").import_xml stylesheet = os.path.join(current.request.folder, "static", "formats", "cap", "import.xsl") try: file = fetch(url) except HTTPError as e: import base64 rss_table = s3db.msg_rss_channel query = (rss_table.channel_id == record.channel_id) channel = db(query).select(rss_table.date, rss_table.etag, rss_table.url, rss_table.username, rss_table.password, limitby=(0, 1)).first() username = channel.username password = channel.password if e.code == 401 and username and password: request = urllib2.Request(url) base64string = base64.encodestring("%s:%s" % (username, password)) request.add_header("Authorization", "Basic %s" % base64string) else: request = None try: file = urlopen(request).read() if request else fetch(url) except HTTPError as e: # Check if there are links to look into ltable = s3db.msg_rss_link query_ = (ltable.rss_id == record.id) & (ltable.deleted != True) rows_ = db(query_).select(ltable.type, ltable.url) url_format = "{uri.scheme}://{uri.netloc}/".format url_domain = url_format(uri=urlparse.urlparse(url)) for row_ in rows_: url = row_.url if url and row_.type == "application/cap+xml" and \ url_domain == url_format(uri=urlparse.urlparse(url)): # Same domain, so okey to use same username/pwd combination if e.code == 401 and username and password: request = urllib2.Request(url) request.add_header("Authorization", "Basic %s" % base64string) else: request = None try: file = urlopen( request).read() if request else fetch(url) except HTTPError as e: current.log.error( "Getting content from link failed: %s" % e) else: # Import via XSLT import_xml(StringIO(file), stylesheet=stylesheet, ignore_errors=True) else: # Import via XSLT import_xml(StringIO(file), stylesheet=stylesheet, ignore_errors=True) else: # Public Alerts # eg. http://host.domain/eden/cap/public/xx.cap # Import via XSLT import_xml(StringIO(file), stylesheet=stylesheet, ignore_errors=True) # No Reply return
def http( self, method="GET", path=None, args=None, data=None, headers=None, auth=False, encode="json", decode="json", ): """ Send a HTTP request to the REST API @param method: the HTTP method @param path: the path relative to the base URL of the service @param args: dict of URL parameters @param data: data to send (JSON-serializable object) @param auth: False - do not send an Auth header "Basic" - send an Auth header with username+password "Token" - send an Auth header with access token @param encode: encode the request data as "json"|"text"|"bytes" @param decode: decode the response as "json"|"text"|"bytes" """ base_url = self.base_url if not base_url: return None, None, "No base URL set" url = base_url.rstrip("/") if path: url = "/".join((url, path.lstrip("/"))) if args: url = "?".join((url, urlencode(args))) # Generate the Request if PY2: req = urllib2.Request(url) req.get_method = lambda: method else: req = urllib2.Request(url=url, method=method) # Request data if method == "GET": request_data = None elif data: if encode == "json": request_data = json.dumps(data).encode("utf-8") req.add_header("Content-Type", "application/json") elif encode == "text": request_data = s3_str(data).encode("utf-8") req.add_header("Content-Type", "text/plain; charset=UTF-8") else: request_data = s3_str(data).encode("utf-8") req.add_header("Content-Type", "application/octet-stream") else: request_data = None # Acceptable response type if decode == "json": req.add_header("Accept", "application/json") else: req.add_header("Accept", "*/*") # Run the request output = status = error = None opener = self._http_opener(req, headers=headers, auth=auth) try: f = opener.open(req, data=request_data) except HTTPError as e: # HTTP error status status = e.code error = s3_str(e.read()) except URLError as e: # Network Error error = e.reason if not error: error = "Unknown network error" except Exception: # Other Error error = sys.exc_info()[1] else: status = f.code # Decode the response if decode == "json": try: output = json.load(f) except JSONERRORS: error = sys.exc_info()[1] elif decode == "text": output = s3_str(f.read()) else: # return the stream as-is output = f return output, status, error
def _send_request(self, method="GET", **args): repository = self.repository config = repository.config # Authentication args = Storage(args) if hasattr(self, "PHPSESSID") and self.PHPSESSID: args["PHPSESSID"] = self.PHPSESSID if hasattr(self, "api_key") and self.api_key: args["api_key"] = self.api_key if repository.site_key: args["key"] = repository.site_key # Create the request url = repository.url + "?" + urlencode(args) req = urllib2.Request(url=url) handlers = [] # Proxy handling proxy = repository.proxy or config.proxy or None if proxy: # Figure out the protocol from the URL url_split = url.split("://", 1) if len(url_split) == 2: protocol = url_split[0] else: protocol = "http" current.log.debug("using proxy=%s", proxy) proxy_handler = urllib2.ProxyHandler({protocol: proxy}) handlers.append(proxy_handler) # Install all handlers if handlers: opener = urllib2.build_opener(*handlers) urllib2.install_opener(opener) # Execute the request response = None message = None try: if method == "POST": f = urlopen(req, data="") else: f = urlopen(req) except HTTPError as e: message = "HTTP %s: %s" % (e.code, e.reason) else: # Parse the response tree = current.xml.parse(f) root = tree.getroot() is_error = root.xpath("//ResultSet[1]/Result[1]/is_error") if len(is_error) and int(is_error[0].text): error = root.xpath("//ResultSet[1]/Result[1]/error_message") if len(error): message = error[0].text else: message = "Unknown error" else: response = tree return response, message
def _send_request(self, method="GET", path=None, args=None, data=None, auth=False): """ Send a request to the Wrike API @param method: the HTTP method @param path: the path relative to the repository URL @param data: the data to send @param auth: this is an authorization request """ repository = self.repository # Request URL api = "oauth2/token" if auth else "api/v3" url = "/".join((repository.url.rstrip("/"), api)) if path: url = "/".join((url, path.lstrip("/"))) if args: url = "?".join((url, urlencode(args))) # Create the request req = urllib2.Request(url=url) handlers = [] if not auth: # Install access token header access_token = self.access_token if not access_token: message = "Authorization failed: no access token" current.log.error(message) return None, message req.add_header("Authorization", "%s %s" % (self.token_type, access_token)) # JSONify request data request_data = json.dumps(data) if data else "" if request_data: req.add_header("Content-Type", "application/json") else: # URL-encode request data for auth request_data = urlencode(data) if data else "" # Indicate that we expect JSON response req.add_header("Accept", "application/json") # Proxy handling config = repository.config proxy = repository.proxy or config.proxy or None if proxy: current.log.debug("using proxy=%s" % proxy) proxy_handler = urllib2.ProxyHandler({"https": proxy}) handlers.append(proxy_handler) # Install all handlers if handlers: opener = urllib2.build_opener(*handlers) urllib2.install_opener(opener) # Execute the request response = None message = None try: if method == "POST": f = urlopen(req, data=request_data) else: f = urlopen(req) except HTTPError as e: message = "HTTP %s: %s" % (e.code, e.reason) else: # Parse the response try: response = json.load(f) except ValueError as e: message = sys.exc_info()[1] return response, message
def _send_request(self, method="GET", path=None, args=None, data=None, auth=False): """ Send a request to the CommandBridge API @param method: the HTTP method @param path: the path relative to the repository URL @param data: the data to send @param auth: this is an authorization request """ xml = current.xml repository = self.repository # Request URL url = repository.url.rstrip("/") if path: url = "/".join((url, path.lstrip("/"))) if args: url = "?".join((url, urlencode(args))) # Create the request req = urllib2.Request(url=url) handlers = [] site_key = repository.site_key if not site_key: message = "CommandBridge Authorization failed: no access token (site key)" current.log.error(message) return None, message req.add_header("Authorization-Token", "%s" % site_key) # Request Data request_data = data if data is not None else "" if request_data: req.add_header("Content-Type", "application/xml") # Indicate that we expect XML response req.add_header("Accept", "application/xml") # Proxy handling config = repository.config proxy = repository.proxy or config.proxy or None if proxy: current.log.debug("using proxy=%s" % proxy) proxy_handler = urllib2.ProxyHandler({"https": proxy}) handlers.append(proxy_handler) # Install all handlers if handlers: opener = urllib2.build_opener(*handlers) urllib2.install_opener(opener) # Execute the request response = None message = None try: if method == "POST": f = urlopen(req, data=request_data) else: f = urlopen(req) except HTTPError as e: message = "HTTP %s: %s" % (e.code, e.reason) # More details may be in the response body error_response = xml.parse(e) if error_response: error_messages = error_response.findall("Message") details = " / ".join(item.text for item in error_messages) message = "%s (%s)" % (message, details) else: response = xml.parse(f) if response is None: if method == "POST": response = True elif xml.error: message = xml.error return response, message
def notify(cls, resource_id): """ Asynchronous task to notify a subscriber about updates, runs a POST?format=msg request against the subscribed controller which extracts the data and renders and sends the notification message (see send()). @param resource_id: the pr_subscription_resource record ID """ _debug = current.log.debug _debug("S3Notifications.notify(resource_id=%s)" % resource_id) db = current.db s3db = current.s3db stable = s3db.pr_subscription rtable = db.pr_subscription_resource ftable = s3db.pr_filter # Extract the subscription data join = stable.on(rtable.subscription_id == stable.id) left = ftable.on(ftable.id == stable.filter_id) # @todo: should not need rtable.resource here row = db(rtable.id == resource_id).select(stable.id, stable.pe_id, stable.frequency, stable.notify_on, stable.method, stable.email_format, stable.attachment, rtable.id, rtable.resource, rtable.url, rtable.last_check_time, ftable.query, join=join, left=left).first() if not row: return True s = getattr(row, "pr_subscription") r = getattr(row, "pr_subscription_resource") f = getattr(row, "pr_filter") # Create a temporary token to authorize the lookup request auth_token = str(uuid4()) # Store the auth_token in the subscription record r.update_record(auth_token=auth_token) db.commit() # Construct the send-URL public_url = current.deployment_settings.get_base_public_url() lookup_url = "%s/%s/%s" % (public_url, current.request.application, r.url.lstrip("/")) # Break up the URL into its components purl = list(urlparse.urlparse(lookup_url)) # Subscription parameters # Date (must ensure we pass to REST as tz-aware) last_check_time = s3_encode_iso_datetime(r.last_check_time) query = {"subscription": auth_token, "format": "msg"} if "upd" in s.notify_on: query["~.modified_on__ge"] = "%sZ" % last_check_time else: query["~.created_on__ge"] = "%sZ" % last_check_time # Filters if f.query: from .s3filter import S3FilterString resource = s3db.resource(r.resource) fstring = S3FilterString(resource, f.query) for k, v in fstring.get_vars.items(): if v is not None: if k in query: value = query[k] if type(value) is list: value.append(v) else: query[k] = [value, v] else: query[k] = v query_nice = s3_unicode(fstring.represent()) else: query_nice = None # Add subscription parameters and filters to the URL query, and # put the URL back together query = urlencode(query) if purl[4]: query = "&".join((purl[4], query)) page_url = urlparse.urlunparse([purl[0], # scheme purl[1], # netloc purl[2], # path purl[3], # params query, # query purl[5], # fragment ]) # Serialize data for send (avoid second lookup in send) data = json.dumps({"pe_id": s.pe_id, "notify_on": s.notify_on, "method": s.method, "email_format": s.email_format, "attachment": s.attachment, "resource": r.resource, "last_check_time": last_check_time, "filter_query": query_nice, "page_url": lookup_url, "item_url": None, }) # Send the request _debug("Requesting %s" % page_url) req = urllib2.Request(page_url, data=data.encode("utf-8")) req.add_header("Content-Type", "application/json") success = False try: response = json.loads(urlopen(req).read()) message = response["message"] if response["status"] == "success": success = True except HTTPError as e: message = ("HTTP %s: %s" % (e.code, e.read())) except: exc_info = sys.exc_info()[:2] message = ("%s: %s" % (exc_info[0].__name__, exc_info[1])) _debug(message) # Update time stamps and unlock, invalidate auth token intervals = s3db.pr_subscription_check_intervals interval = datetime.timedelta(minutes=intervals.get(s.frequency, 0)) if success: last_check_time = datetime.datetime.utcnow() next_check_time = last_check_time + interval r.update_record(auth_token=None, locked=False, last_check_time=last_check_time, next_check_time=next_check_time) else: r.update_record(auth_token=None, locked=False) db.commit() # Done return message