From 235e7c55163d347be3bc78f1c1e2d6390d0061e8 Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Mon, 18 Apr 2022 17:21:25 +0100 Subject: [PATCH] Fix ad-related methods in LBTC --- handler/lib/localbitcoins_py.py | 294 +++++++++++++++----------------- 1 file changed, 141 insertions(+), 153 deletions(-) diff --git a/handler/lib/localbitcoins_py.py b/handler/lib/localbitcoins_py.py index ffabb91..0a023ec 100644 --- a/handler/lib/localbitcoins_py.py +++ b/handler/lib/localbitcoins_py.py @@ -8,9 +8,7 @@ from typing import Dict from typing import List from typing import Optional from typing import Union - import arrow -import httpx # Project imports import util @@ -37,7 +35,7 @@ logging.getLogger("requests.packages.urllib3").setLevel(logging.INFO) logging.getLogger("urllib3.connectionpool").setLevel(logging.INFO) logger = util.get_logger(__name__) -URI_API = "https://localbitcoins.com/api/" +URI_API = "https://localbitcoins.com/" SERVER = "https://localbitcoins.com" @@ -81,19 +79,16 @@ class LocalBitcoins: """ # Calculate signature message = nonce + self.hmac_key + url.encode("ascii") - print("message", message) if params_encoded: if sys.version_info >= (3, 0) and isinstance(params_encoded, str): message += params_encoded.encode("ascii") - print("after message appended", message) else: message += params_encoded signature = hmac_lib.new(self.hmac_secret, msg=message, digestmod=hashlib.sha256).hexdigest().upper() - print("signature", signature) return signature - def encode_params(self, api_method, api_call_url, query_values): - if api_method == "POST": + def encode_params(self, http_method, api_call_url, query_values): + if http_method == "POST": api_request = requests.Request("POST", api_call_url, data=query_values).prepare() params_encoded = api_request.body @@ -101,7 +96,7 @@ class LocalBitcoins: else: api_request = requests.Request("GET", api_call_url, params=query_values).prepare() params_encoded = urlparse(api_request.url).query - return params_encoded + return (api_request, params_encoded) def _api_call( self, @@ -110,7 +105,6 @@ class LocalBitcoins: query_values: Optional[Dict[str, Any]] = None, files: Optional[Any] = None, ) -> Dict[str, Any]: - api_method += "/" api_call_url = URI_API + api_method url = api_call_url @@ -118,18 +112,16 @@ class LocalBitcoins: url = url[len(SERVER) :] # noqa # HMAC crypto stuff - params_encoded = self.encode_params(api_method, api_call_url, query_values) + api_request, params_encoded = self.encode_params(http_method, api_call_url, query_values) nonce = str(int(time.time() * 1000)).encode("ascii") signature = self.sign_payload(nonce, url, params_encoded) - headers = { - "Apiauth-Key": self.hmac_key, - "Apiauth-Nonce": nonce, - "Apiauth-Signature": signature, - } + api_request.headers["Apiauth-Key"] = self.hmac_key + api_request.headers["Apiauth-Nonce"] = nonce + api_request.headers["Apiauth-Signature"] = signature logger.debug("API Call URL: %s", api_call_url) - logger.debug("Headers : %s", headers) + logger.debug("Headers : %s", api_request.headers) logger.debug("HTTP Method : %s", http_method) logger.debug("Query Values: %s", query_values) logger.debug("Query Values as Json:\n%s", json.dumps(query_values)) @@ -140,36 +132,21 @@ class LocalBitcoins: "response": None, "status": None, } - + session = requests.Session() try: - response = None - if http_method == "POST": - if query_values: - response = httpx.post( - url=api_call_url, - headers=headers, - content=json.dumps(query_values), - ) - else: - response = httpx.post( - url=api_call_url, - headers=headers, - ) - - else: - response = httpx.get(url=api_call_url, headers=headers, params=query_values) - - logger.debug(response) - result["response"] = json.loads(response.text) + response = session.send(api_request) + response_json = response.json() + result["response"] = response_json result["status"] = response.status_code if response.status_code == 200: result["success"] = True result["message"] = "OK" else: result["message"] = "API ERROR" - print("RESP", result) + # print("RESP", result) return result - except httpx.ConnectError as error: + + except requests.ConnectionError as error: result["message"] = str(error) result["status"] = 600 result["response"] = {"error": {"message": error}} @@ -180,7 +157,7 @@ class LocalBitcoins: result["status"] = response.status_code result["response"] = {"error": {"message": response.text}} return result - except httpx.ReadTimeout: + except requests.ReadTimeout: result["message"] = "Read timed out" if response: result["status"] = response.status_code @@ -195,14 +172,14 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#account_info """ - return self._api_call(api_method=f"account_info/{username}") + return self._api_call(api_method=f"api/account_info/{username}/") def dashboard(self) -> Dict[str, Any]: """See LocalBitcoins API. https://localbitcoins.com/api-docs/#dashboard """ - return self._api_call(api_method="dashboard") + return self._api_call(api_method="api/dashboard/") # def dashboard_buyer(self) -> Dict[str, Any]: # """See LocalBitcoins API. @@ -223,14 +200,14 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#dashboard-canceled """ - return self._api_call(api_method="dashboard/canceled") + return self._api_call(api_method="api/dashboard/canceled/") def dashboard_closed(self) -> Dict[str, Any]: """See LocalBitcoins API. https://localbitcoins.com/api-docs/#dashboard-closed """ - return self._api_call(api_method="dashboard/closed") + return self._api_call(api_method="api/dashboard/closed/") def dashboard_released(self) -> Dict[str, Any]: """See LocalBitcoins API. @@ -238,7 +215,7 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#dashboard-released """ - return self._api_call(api_method="dashboard/released") + return self._api_call(api_method="api/dashboard/released/") def logout(self) -> Dict[str, Any]: """See LocalBitcoins API. @@ -246,7 +223,7 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#logout """ - return self._api_call(api_method="logout", http_method="POST") + return self._api_call(api_method="api/logout/", http_method="POST") def myself(self) -> Dict[str, Any]: """See LocalBitcoins API. @@ -254,7 +231,7 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#myself """ - return self._api_call(api_method="myself") + return self._api_call(api_method="api/myself/") def notifications(self) -> Dict[str, Any]: """See LocalBitcoins API. @@ -262,7 +239,7 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#notifications """ - return self._api_call(api_method="notifications") + return self._api_call(api_method="api/notifications/") def notifications_mark_as_read(self, notification_id: str) -> Dict[str, Any]: """See LocalBitcoins API. @@ -271,7 +248,7 @@ class LocalBitcoins: """ return self._api_call( - api_method=f"notifications/mark_as_read/{notification_id}", + api_method=f"notifications/mark_as_read/{notification_id}/", http_method="POST", ) @@ -281,7 +258,7 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#recent-messages """ - return self._api_call(api_method="recent_messages") + return self._api_call(api_method="api/recent_messages/") # Trade related API Methods # =========================== @@ -297,7 +274,7 @@ class LocalBitcoins: if msg: params["msg"] = msg return self._api_call( - api_method=f"feedback/{username}", + api_method=f"feedback/{username}/", http_method="POST", query_values=params, ) @@ -313,7 +290,7 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#contact-paid """ - return self._api_call(api_method=f"contact_mark_as_paid/{trade_id}", http_method="POST") + return self._api_call(api_method=f"contact_mark_as_paid/{trade_id}/", http_method="POST") # post/contact_cancel/{trade_id} • Cancel the trade def contact_cancel( @@ -340,11 +317,11 @@ class LocalBitcoins: """ if after: reply = self._api_call( - api_method=f"contact_messages/{trade_id}", + api_method=f"contact_messages/{trade_id}/", query_values={"after": after.to("UTC").isoformat()}, ) else: - reply = self._api_call(api_method=f"contact_messages/{trade_id}") + reply = self._api_call(api_method=f"contact_messages/{trade_id}/") return reply @@ -363,7 +340,7 @@ class LocalBitcoins: if msg: payload["msg"] = msg return self._api_call( - api_method=f"contact_create/{ad_id}", + api_method=f"contact_create/{ad_id}/", http_method="POST", query_values=payload, ) @@ -375,7 +352,7 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#contact-info-id and https://localbitcoins.com/api-docs/#contact-info """ - api_method = "contact_info" + api_method = "contact_info/" if isinstance(trade_ids, list): params = "?contacts=" for trade_id in trade_ids: @@ -395,7 +372,7 @@ class LocalBitcoins: """ payload = {"msg": msg} return self._api_call( - api_method=f"contact_message_post/{trade_id}", + api_method=f"contact_message_post/{trade_id}/", http_method="POST", query_values=payload, ) @@ -406,29 +383,32 @@ class LocalBitcoins: # Advertisement related API Methods # ================================ - def ad_create( # TODO: fill fields + def ad_create( self, country_code: str, currency: str, trade_type: str, - asset: str, price_equation: str, track_max_amount: bool, require_trusted_by_advertiser: bool, - verified_email_required: Optional[bool] = None, + bank_name: str, + sms_verification_required: Optional[bool] = None, + require_identification: Optional[bool] = None, online_provider: Optional[str] = None, msg: Optional[str] = None, min_amount: Optional[float] = None, max_amount: Optional[float] = None, - limit_to_fiat_amounts: Optional[str] = None, - payment_method_details: Optional[str] = None, - first_time_limit_asset: Optional[float] = None, - require_feedback_score: Optional[int] = None, account_info: Optional[str] = None, - payment_window_minutes: Optional[int] = None, - floating: Optional[bool] = None, - lat: Optional[float] = None, - lon: Optional[float] = None, + first_time_limit_btc: Optional[float] = None, + require_feedback_score: Optional[int] = None, + city: Optional[str] = None, + location_string: Optional[str] = None, + opening_hours: Optional[dict] = None, + visible: Optional[bool] = True, + require_trade_volume: Optional[float] = None, + volume_coefficient_btc: Optional[float] = None, + reference_type: Optional[str] = None, + display_reference: Optional[bool] = None, ) -> Dict[str, Any]: """See LocalBitcoins API. @@ -445,13 +425,14 @@ class LocalBitcoins: "countrycode": country_code, "currency": currency, "trade_type": trade_type, - "asset": asset, "price_equation": price_equation, - "track_max_amount": 1 if track_max_amount else 0, - "require_trusted_by_advertiser": 1 if require_trusted_by_advertiser else 0, + "track_max_amount": track_max_amount, + "require_trusted_by_advertiser": require_trusted_by_advertiser, } - if verified_email_required: - params["verified_email_required"] = 1 if verified_email_required else 0 + if sms_verification_required: + params["sms_verification_required"] = True + if require_identification: + params["require_identification"] = True if online_provider: params["online_provider"] = online_provider if msg: @@ -460,27 +441,33 @@ class LocalBitcoins: params["min_amount"] = min_amount if max_amount: params["max_amount"] = max_amount - if limit_to_fiat_amounts: - params["limit_to_fiat_amounts"] = limit_to_fiat_amounts - if payment_method_details: - params["payment_method_detail"] = payment_method_details - if first_time_limit_asset: - params["first_time_limit_asset"] = first_time_limit_asset + if first_time_limit_btc: + params["first_time_limit_btc"] = first_time_limit_btc if require_feedback_score: params["require_feedback_score"] = require_feedback_score if account_info: params["account_info"] = account_info - if payment_window_minutes: - params["payment_window_minutes"] = payment_window_minutes - if floating: - params["floating"] = 1 if floating else 0 - if lat: - params["lat"] = lat - if lon: - params["lon"] = lon + if opening_hours: + params["opening_hours"] = opening_hours + if city: + params["city"] = city + if location_string: + params["location_string"] = location_string + if bank_name: + params["bank_name"] = bank_name + if visible: + params["visible"] = visible + if require_trade_volume: + params["require_trade_volume"] = require_trade_volume + if volume_coefficient_btc: + params["volume_coefficient_btc"] = volume_coefficient_btc + if reference_type: + params["reference_type"] = reference_type + if display_reference is not None: + params["display_reference"] = display_reference return self._api_call( - api_method="ad-create", + api_method="api/ad-create/", http_method="POST", query_values=params, ) @@ -488,28 +475,30 @@ class LocalBitcoins: def ad( self, ad_id: str, - country_code: Optional[str] = None, - currency: Optional[str] = None, - trade_type: Optional[str] = None, - asset: Optional[str] = None, - price_equation: Optional[str] = None, - track_max_amount: Optional[bool] = None, - require_trusted_by_advertiser: Optional[bool] = None, - verified_email_required: Optional[bool] = None, + country_code: str, + currency: str, + trade_type: str, + price_equation: str, + track_max_amount: bool, + require_trusted_by_advertiser: bool, + bank_name: str, + sms_verification_required: Optional[bool] = None, + require_identification: Optional[bool] = None, online_provider: Optional[str] = None, msg: Optional[str] = None, min_amount: Optional[float] = None, max_amount: Optional[float] = None, - limit_to_fiat_amounts: Optional[str] = None, - payment_method_details: Optional[str] = None, - first_time_limit_asset: Optional[float] = None, - require_feedback_score: Optional[int] = None, account_info: Optional[str] = None, - payment_window_minutes: Optional[int] = None, - floating: Optional[bool] = None, - lat: Optional[float] = None, - lon: Optional[float] = None, - visible: Optional[bool] = None, + first_time_limit_btc: Optional[float] = None, + require_feedback_score: Optional[int] = None, + city: Optional[str] = None, + location_string: Optional[str] = None, + opening_hours: Optional[dict] = None, + visible: Optional[bool] = True, + require_trade_volume: Optional[float] = None, + volume_coefficient_btc: Optional[float] = None, + reference_type: Optional[str] = None, + display_reference: Optional[bool] = None, ) -> Dict[str, Any]: """See LocalBitcoins API. @@ -524,23 +513,18 @@ class LocalBitcoins: # API takes this many arguments, I can't change that # Too many locals and too many branches goes hand in hand # with too many arguments - params: Dict[str, Union[str, float, bool]] = {} - if country_code: - params["countrycode"] = country_code - if currency: - params["currency"] = currency - if trade_type: - params["trade_type"] = trade_type - if asset: - params["asset"] = asset - if price_equation: - params["price_equation"] = price_equation - if track_max_amount: - params["track_max_amount"] = 1 if track_max_amount else 0 - if require_trusted_by_advertiser: - params["require_trusted_by_advertiser"] = 1 if require_trusted_by_advertiser else 0 - if verified_email_required: - params["verified_email_required"] = 1 if verified_email_required else 0 + params: Dict[str, Any] = { + "countrycode": country_code, + "currency": currency, + "trade_type": trade_type, + "price_equation": price_equation, + "track_max_amount": track_max_amount, + "require_trusted_by_advertiser": require_trusted_by_advertiser, + } + if sms_verification_required: + params["sms_verification_required"] = True + if require_identification: + params["require_identification"] = True if online_provider: params["online_provider"] = online_provider if msg: @@ -549,29 +533,33 @@ class LocalBitcoins: params["min_amount"] = min_amount if max_amount: params["max_amount"] = max_amount - if limit_to_fiat_amounts: - params["limit_to_fiat_amounts"] = limit_to_fiat_amounts - if payment_method_details: - params["payment_method_detail"] = payment_method_details - if first_time_limit_asset: - params["first_time_limit_asset"] = first_time_limit_asset + if first_time_limit_btc: + params["first_time_limit_btc"] = first_time_limit_btc if require_feedback_score: params["require_feedback_score"] = require_feedback_score if account_info: params["account_info"] = account_info - if payment_window_minutes: - params["payment_window_minutes"] = payment_window_minutes - if floating: - params["floating"] = 1 if floating else 0 - if lat: - params["lat"] = lat - if lon: - params["lon"] = lon + if opening_hours: + params["opening_hours"] = opening_hours + if city: + params["city"] = city + if location_string: + params["location_string"] = location_string + if bank_name: + params["bank_name"] = bank_name if visible: - params["visible"] = True if visible else False + params["visible"] = visible + if require_trade_volume: + params["require_trade_volume"] = require_trade_volume + if volume_coefficient_btc: + params["volume_coefficient_btc"] = volume_coefficient_btc + if reference_type: + params["reference_type"] = reference_type + if display_reference is not None: + params["display_reference"] = display_reference return self._api_call( - api_method=f"ad/{ad_id}", + api_method=f"api/ad/{ad_id}/", http_method="POST", query_values=params, ) @@ -582,7 +570,7 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#ad-equation-id """ return self._api_call( - api_method=f"ad-equation/{ad_id}", + api_method=f"ad-equation/{ad_id}/", http_method="POST", query_values={"price_equation": price_equation}, ) @@ -592,7 +580,7 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#ad-delete """ - return self._api_call(api_method=f"ad-delete/{ad_id}", http_method="POST") + return self._api_call(api_method=f"ad-delete/{ad_id}/", http_method="POST") def ads( self, @@ -628,9 +616,9 @@ class LocalBitcoins: params["payment_method_code"] = payment_method_code if len(params) == 0: - return self._api_call(api_method="ads") + return self._api_call(api_method="api/ads/") - return self._api_call(api_method="ads", query_values=params) + return self._api_call(api_method="api/ads/", query_values=params) def ad_get(self, ad_ids: List[str]) -> Dict[str, Any]: """See LocalBitcoins API. @@ -638,7 +626,7 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#ad-get and hhttps://localbitcoins.com/api-docs/#ad-get-id """ - api_method = "ad-get" + api_method = "ad-get/" params = None ids = str(ad_ids)[1:-1].replace(" ", "").replace("'", "") @@ -654,7 +642,7 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#payment-methods and https://localbitcoins.com/api-docs/#payment_methods-cc """ - api_method = "payment_methods" + api_method = "payment_methods/" if country_code: api_method += f"/{country_code}" return self._api_call(api_method=api_method) @@ -664,14 +652,14 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#countrycodes """ - return self._api_call(api_method="countrycodes") + return self._api_call(api_method="api/countrycodes/") def currencies(self) -> Dict[str, Any]: """See LocalBitcoins API. https://localbitcoins.com/api-docs/#currencies """ - return self._api_call(api_method="currencies") + return self._api_call(api_method="api/currencies/") def equation(self, price_equation: str, currency: str) -> Dict[str, Any]: """See LocalBitcoins API. @@ -679,7 +667,7 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#equation """ return self._api_call( - api_method="equation", + api_method="api/equation/", http_method="POST", query_values={ "price_equation": price_equation, @@ -795,7 +783,7 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#ticker-all """ - return self._api_call(api_method="bitcoinaverage/ticket-all-currencies") + return self._api_call(api_method="api/bitcoinaverage/ticket-all-currencies/") # Wallet related API Methods # =========================== @@ -805,28 +793,28 @@ class LocalBitcoins: https://localbitcoins.com/api-docs/#wallet """ - return self._api_call(api_method="wallet") + return self._api_call(api_method="api/wallet/") def wallet_balance(self) -> Dict[str, Any]: """See LocalBitcoins API. https://localbitcoins.com/api-docs/#wallet-balance """ - return self._api_call(api_method="wallet-balance") + return self._api_call(api_method="api/wallet-balance/") def wallet_addr(self) -> Dict[str, Any]: """See LocalBitcoins API. https://localbitcoins.com/api-docs/#wallet-addr """ - return self._api_call(api_method="wallet-addr") + return self._api_call(api_method="api/wallet-addr/") def fees(self) -> Dict[str, Any]: """See LocalBitcoins API. https://localbitcoins.com/api-docs/#fees """ - return self._api_call(api_method="fees") + return self._api_call(api_method="api/fees/") def wallet_send_pin( self, @@ -852,7 +840,7 @@ class LocalBitcoins: params["pincode"] = pincode return self._api_call( - api_method="wallet-send-pin", + api_method="api/wallet-send-pin/", http_method="POST", query_values=params, )