def login_url(self, next="/"): """ Overriding to produce a different redirect_uri """ if not self.accessToken(): request = current.request session = current.session if not request.vars.code: session.redirect_uri = self.args["redirect_uri"] data = { "redirect_uri": session.redirect_uri, "response_type": "code", "client_id": self.client_id, } if self.args: data.update(self.args) auth_request_url = "%s?%s" % ( self.auth_url, urlencode(data), ) raise HTTP( 307, REDIRECT_MSG % auth_request_url, Location=auth_request_url, ) else: session.code = request.vars.code self.accessToken() return next
def geocode(self, query, *, exactly_one=True, timeout=DEFAULT_SENTINEL, country=None, country_bias=None): """ Return a location point by address. :param str query: The address or query you wish to geocode. :param bool exactly_one: Return one result or a list of results, if available. :param int timeout: Time, in seconds, to wait for the geocoding service to respond before raising a :class:`geopy.exc.GeocoderTimedOut` exception. Set this only if you wish to override, on this call only, the value set during the geocoder's initialization. :param country: Limit records to the specified countries. Two letter country code ISO-3166 (e.g. ``FR``). Might be a single string or a list of strings. :type country: str or list :param str country_bias: Records from the country_bias are listed first. Two letter country code ISO-3166. :rtype: ``None``, :class:`geopy.location.Location` or a list of them, if ``exactly_one=False``. """ params = [ ('name_startsWith', query), ] #if country_bias: # params.append(('countryBias', country_bias)) #if not country: # country = [] #if isinstance(country, str): # country = [country] #for country_item in country: # params.append(('country', country_item)) if exactly_one: params.append(('maxRows', 1)) url = "&".join((self.api, urlencode(params))) logger.debug("%s.geocode: %s", self.__class__.__name__, url) callback = partial(self._parse_json, exactly_one=exactly_one) return self._call_geocoder(url, callback, timeout=timeout)
def accessToken(self): """ Return the access token generated by the authenticating server. If token is already in the session that one will be used. Otherwise the token is fetched from the auth server. """ session = current.session token = session.token if token and "expires" in token: expires = token["expires"] # reuse token until expiration if expires == 0 or expires > time.time(): return token["access_token"] code = session.code if code: data = { "client_id": self.client_id, "client_secret": self.client_secret, "redirect_uri": self.args["redirect_uri"], "code": code, "grant_type": "authorization_code", "scope": self.args["scope"], } open_url = None opener = self.__build_url_opener(self.token_url) try: open_url = opener.open(self.token_url, urlencode(data)) except HTTPError as e: raise Exception(e.read()) finally: del session.code # throw it away if open_url: try: token = json.loads(open_url.read()) token["expires"] = int(token["expires_in"]) + time.time() finally: opener.close() session.token = token return token["access_token"] session.token = None return None
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