From 262cf36ecaf13b1b9c1013b9194d64450d0d4727 Mon Sep 17 00:00:00 2001
From: Vincent Texier <vit@free.fr>
Date: Mon, 9 Jul 2018 11:36:49 +0200
Subject: [PATCH] issue #56 WIP - Add Client.post() method + update send
 membership example

---
 duniterpy/api/bma/blockchain.py | 23 ++++++------
 duniterpy/api/client.py         | 33 ++++++++++++++++-
 examples/send_membership.py     | 63 ++++++++++++++++-----------------
 3 files changed, 74 insertions(+), 45 deletions(-)

diff --git a/duniterpy/api/bma/blockchain.py b/duniterpy/api/bma/blockchain.py
index a10a6e3c..c79b8ecc 100644
--- a/duniterpy/api/bma/blockchain.py
+++ b/duniterpy/api/bma/blockchain.py
@@ -16,7 +16,7 @@
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
 # vit
 import logging
-from duniterpy.api.client import Client
+from duniterpy.api.client import Client, RESPONSE_AIOHTTP
 
 logger = logging.getLogger("duniter/blockchain")
 
@@ -323,17 +323,16 @@ async def memberships(client: Client, search: str) -> dict:
     return await client.get(MODULE + '/memberships/%s' % search, schema=MEMBERSHIPS_SCHEMA)
 
 
-# async def membership(connection, membership):
-#     """
-#     POST a Membership document
-#
-#     :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-#     :param str membership: Membership signed raw document
-#     :rtype: aiohttp.ClientResponse
-#     """
-#     client = API(connection, MODULE)
-#
-#     return await client.requests_post('/membership', membership=membership)
+async def membership(client: Client, _membership: str):
+    """
+    POST a Membership document
+
+    :param client: Client to connect to the api
+    :param _membership: Membership signed raw document
+    :rtype: aiohttp.ClientResponse
+    """
+    return await client.post(MODULE + '/membership', {'membership': _membership}, rtype=RESPONSE_AIOHTTP)
+
 
 async def current(client: Client) -> dict:
     """
diff --git a/duniterpy/api/client.py b/duniterpy/api/client.py
index 07fb374a..19c9c4af 100644
--- a/duniterpy/api/client.py
+++ b/duniterpy/api/client.py
@@ -198,7 +198,7 @@ class Client:
 
     async def get(self, url_path: str, params: dict = None, rtype: str = RESPONSE_JSON, schema: dict = None)-> any:
         """
-        Get request on self.endpoint + url_path
+        GET request on self.endpoint + url_path
 
         :param url_path: Url encoded path following the endpoint
         :param params: Url query string parameters dictionary
@@ -227,6 +227,37 @@ class Client:
         elif rtype == RESPONSE_JSON:
             return await response.json()
 
+    async def post(self, url_path: str, params: dict = None, rtype: str = RESPONSE_JSON, schema: dict = None)-> any:
+        """
+        POST request on self.endpoint + url_path
+
+        :param url_path: Url encoded path following the endpoint
+        :param params: Url query string parameters dictionary
+        :param rtype: Response type
+        :param schema: Json Schema to validate response (optional, default None)
+        :return:
+        """
+        if params is None:
+            params = dict()
+
+        client = API(self.endpoint.conn_handler(self.session, self.proxy), '')
+
+        # get aiohttp response
+        response = await client.requests_post(url_path, **params)
+
+        # if schema supplied...
+        if schema is not None:
+            # validate response
+            await parse_response(response, schema)
+
+        # return the chosen type
+        if rtype == RESPONSE_AIOHTTP:
+            return response
+        elif rtype == RESPONSE_TEXT:
+            return await response.text()
+        elif rtype == RESPONSE_JSON:
+            return await response.json()
+
     async def close(self):
         """
         Close aiohttp session
diff --git a/examples/send_membership.py b/examples/send_membership.py
index 7a85af84..26111d72 100644
--- a/examples/send_membership.py
+++ b/examples/send_membership.py
@@ -1,13 +1,11 @@
 import asyncio
-import aiohttp
 import getpass
 
 import duniterpy.api.bma as bma
-from duniterpy.api.endpoint import SecuredBMAEndpoint
+from duniterpy.api.client import Client
 from duniterpy.documents import BlockUID, Identity, Membership
 from duniterpy.key import SigningKey
 
-
 # CONFIG #######################################
 
 # You can either use a complete defined endpoint : [NAME_OF_THE_API] [DOMAIN] [IPv4] [IPv6] [PORT]
@@ -15,21 +13,18 @@ from duniterpy.key import SigningKey
 # Here we use the secure BASIC_MERKLED_API (BMAS)
 BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443"
 
-################################################
 
-# Latest duniter-python-api is asynchronous and you have to create an aiohttp session to send request
-# ( http://pythonhosted.org/aiohttp )
-AIOHTTP_SESSION = aiohttp.ClientSession()
+################################################
 
 
-def get_identity_document(current_block, uid, salt, password):
+def get_identity_document(current_block: dict, uid: str, salt: str, password: str) -> Identity:
     """
     Get an Identity document
 
-    :param dict current_block: Current block data
-    :param str uid: Unique Identifier
-    :param str salt: Passphrase of the account
-    :param str password: Password of the account
+    :param current_block: Current block data
+    :param uid: Unique Identifier
+    :param salt: Passphrase of the account
+    :param password: Password of the account
 
     :rtype: Identity
     """
@@ -56,15 +51,16 @@ def get_identity_document(current_block, uid, salt, password):
     return identity
 
 
-def get_membership_document(mtype, current_block, identity, salt, password):
+def get_membership_document(membership_type: str, current_block: dict, identity: Identity, salt: str,
+                            password: str) -> Membership:
     """
     Get a Membership document
 
-    :param str mtype: "IN" to ask for membership or "OUT" to cancel membership
-    :param dict current_block: Current block data
-    :param Identity identity: Identity document
-    :param str salt: Passphrase of the account
-    :param str password: Password of the account
+    :param membership_type: "IN" to ask for membership or "OUT" to cancel membership
+    :param current_block: Current block data
+    :param identity: Identity document
+    :param salt: Passphrase of the account
+    :param password: Password of the account
 
     :rtype: Membership
     """
@@ -81,7 +77,7 @@ def get_membership_document(mtype, current_block, identity, salt, password):
         currency=current_block['currency'],
         issuer=key.pubkey,
         membership_ts=timestamp,
-        membership_type=mtype,
+        membership_type=membership_type,
         uid=identity.uid,
         identity_ts=identity.timestamp,
         signature=None
@@ -97,11 +93,15 @@ async def main():
     """
     Main code
     """
-    # connection handler from BMA endpoint
-    connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION)
+    # Create Client from endpoint string in Duniter format
+    client = Client(BMAS_ENDPOINT)
+
+    # Get the node summary infos by dedicated method (with json schema validation)
+    response = await client(bma.node.summary)
+    print(response)
 
     # capture current block to get version and currency and blockstamp
-    current_block = await bma.blockchain.current(connection)
+    current_block = await client(bma.blockchain.current)
 
     # prompt hidden user entry
     salt = getpass.getpass("Enter your passphrase (salt): ")
@@ -110,27 +110,26 @@ async def main():
     password = getpass.getpass("Enter your password: ")
 
     # prompt entry
-    UID = input("Enter your UID: ")
+    uid = input("Enter your UID: ")
 
     # create our signed identity document
-    identity = get_identity_document(current_block, UID, salt, password)
+    identity = get_identity_document(current_block, uid, salt, password)
 
     # create a membership demand document
     membership = get_membership_document("IN", current_block, identity, salt, password)
 
-    # send the membership document to the node
-    response = await bma.blockchain.membership(connection, membership.signed_raw())
+    # send the membership signed raw document to the node
+    response = await client(bma.blockchain.membership, membership.signed_raw())
 
     if response.status == 200:
         print(await response.text())
     else:
         print("Error while publishing membership : {0}".format(await response.text()))
 
-    response.close()
-
+    # Close client aiohttp session
+    await client.close()
 
-with AIOHTTP_SESSION:
 
-    # Latest duniter-python-api is asynchronous and you have to use asyncio, an asyncio loop and a "as" on the data.
-    # ( https://docs.python.org/3/library/asyncio.html )
-    asyncio.get_event_loop().run_until_complete(main())
+# Latest duniter-python-api is asynchronous and you have to use asyncio, an asyncio loop and a "as" on the data.
+# ( https://docs.python.org/3/library/asyncio.html )
+asyncio.get_event_loop().run_until_complete(main())
-- 
GitLab