Browse Source

ark linepay and transfer

ming 2 years ago
parent
commit
fed46f2e6b

+ 53 - 33
app/api/api_v1/endpoints/line.py

@@ -55,7 +55,7 @@ class LineRouter(APIRoute):
                 )
             log_table = db['log']
             try:
-                userid = int(json.loads(base64.b64decode(request.headers['authorization'][7:].split('.')[1]).decode('utf-8'))['sub'])
+                userid = int(json.loads(base64.b64decode(request.headers['authorization'][7:].split('.')[1]+ '=' * (-len(request.headers['authorization'][7:].split('.')[1]) % 4)).decode('utf-8'))['sub'])
             except:
                 if( "/api/v1/line/collection/" or "/api/v1/line/receive/" or "/api/v1/line/shop/" or "/api/v1/line/send" in request.url.path):
                     lineid = request.url.path.split("/")[-1]
@@ -389,8 +389,27 @@ async def send(
 
 # shop handler
 @router.get("/shop/{userid}")
-def shop(userid):
+async def shop(userid:str, db: Session = Depends(deps.get_db)):
     # db connect
+    url = 'accounts/U9dc55544ecca3a95b170bdf2a30e3691/nft_balances'
+    r = await request_get(baseUrl + url, headers)
+    nft_all = {}
+    outcome = r.json()['nft_balances']
+    ii = 0
+    for i in range(len(outcome)):
+        nft_ = crud.nft.get_by_uid(db, uid=outcome[i]['uid'])
+        if nft_:
+            nft_all[ii] = jsonable_encoder(nft_)
+            nft_all[ii].pop('userid')
+            nft_all[ii].pop('is_active')
+            nft_all[ii].pop('uid')
+            nft_all[ii].pop('hash')
+            nft_all[ii].pop('category')
+            nft_all[ii]['amount'] = outcome[i]['amount']
+            nft_all[ii]['price'] = '1'
+            ii += 1
+
+    return nft_all
     db = dataset.connect(
         'mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4'
     )
@@ -407,37 +426,38 @@ def shop(userid):
     db.close()
 
 
-@router.post("/buy")
-async def buy(userModel: line.BuyNft):
-    # db connect
-    db = dataset.connect(
-        'mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4'
-    )
-    table2 = db['nft']
-
-    # input
-    nftid = userModel.nftid
-    userid = userModel.userid
-
-    if not table2.find_one(id=nftid):
-        db.close()
-        # push訊息
-        message = "購買失敗!如果有疑問,請洽網站的服務信箱!"
-        push_text(userid, message)
-        return "該NFT商品不存在!如果有疑問,請洽網站的服務信箱!"
-    else:
-        user_obj = table2.find_one(id=nftid)
-        user_obj['userid'] = userid
-        table2.update(dict(user_obj), ['id'])
-
-        # push訊息
-        result3 = table2.find_one(id=nftid)
-        title = result3['title']
-        message = "您的NFT : " + title + ", 已購買成功!"
-        push_text(userid, message)
-
-        db.close()
-    return "您已購買成功!"
+# @router.post("/buy")
+# async def buy(userModel: line.BuyNft):
+#     # db connect
+#     db = dataset.connect(
+#         'mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4'
+#     )
+#     table2 = db['nft']
+
+#     # input
+#     nftid = userModel.nftid
+#     userid = userModel.userid
+#     amount = userModel.amount
+
+#     if not table2.find_one(id=nftid):
+#         db.close()
+#         # push訊息
+#         message = "購買失敗!如果有疑問,請洽網站的服務信箱!"
+#         push_text(userid, message)
+#         return "該NFT商品不存在!如果有疑問,請洽網站的服務信箱!"
+#     else:
+#         user_obj = table2.find_one(id=nftid)
+#         user_obj['userid'] = userid
+#         table2.update(dict(user_obj), ['id'])
+
+#         # push訊息
+#         result3 = table2.find_one(id=nftid)
+#         title = result3['title']
+#         message = "您的NFT : " + title + ", 已購買成功!"
+#         push_text(userid, message)
+
+#         db.close()
+#     return "您已購買成功!"
 
 
 @router.post("/event")

+ 85 - 17
app/api/api_v1/endpoints/linepay.py

@@ -1,5 +1,10 @@
+import dataset
 import uuid
-
+from datetime import datetime
+from linebot.models import (
+    MessageEvent, TextMessage, TextSendMessage, FollowEvent,
+    TemplateSendMessage, ButtonsTemplate, URITemplateAction,
+)
 from fastapi import APIRouter
 from fastapi.param_functions import Depends
 from linepay import LinePayApi
@@ -7,7 +12,16 @@ from fastapi.templating import Jinja2Templates
 from sqlalchemy.orm.session import Session
 from app import crud, schemas
 from app.api import deps
+from fastapi.encoders import jsonable_encoder
+import requests
+from app.core.config import settings
+
 
+baseUrl = "https://nft-api-staging.joyso.io/api/v1/"
+headers = {
+    'Authorization':
+        'Basic %s' % 'bmZ0OmMxOTEzOWMzYjM3YjdjZWU3ZmY3OTFiZGU3NzdjZWNl'
+}
 # template
 templates = Jinja2Templates(directory="templates")
 
@@ -29,17 +43,20 @@ line = LinePayApi(
 # CACHE
 CACHE = {}
 
-
+def push_text(user, message):
+    settings.line_bot_api.push_message(
+        user, TextSendMessage(text=message)
+    )
 # Request
 @router.post('/request')
 async def pay_request(
-        line_id:str, nft_id: str, db: Session = Depends(deps.get_db)
+        line_id:str, nft_id: str, amount: int,
+        db: Session = Depends(deps.get_db)
     ):
     order_id = str(uuid.uuid4())
-    amount = "1"
     currency = "TWD"
     nft = crud.nft.get(db=db, id=nft_id)
-
+    
     request_options = {
         "amount": amount,
         "currency": currency,
@@ -47,11 +64,11 @@ async def pay_request(
         "packages": [
             {
                 "id": nft.id,
-                "amount": 1,
+                "amount": amount,
                 "products": [
                     {
                         "name": nft.title,
-                        "quantity": 1,
+                        "quantity": amount,
                         "price": 1,
                         "imageUrl": nft.imgurl
                     }
@@ -61,7 +78,8 @@ async def pay_request(
         ],
         "redirectUrls": {
             # "confirmUrl": LINE_PAY_REQEST_BASE_URL + "/confirm/"
-            "confirmUrl": "https://ark.cards/collect.html"
+            "confirmUrl": "https://ark.cards/confirm.html",
+            "cancelUrl" : "https://ark.cards/confirm.html"
             # "cancelUrl": LINE_PAY_REQEST_BASE_URL + "/cancel/"
         }
     }
@@ -78,10 +96,11 @@ async def pay_request(
     )
     payment_obj = schemas.payment.PaymentBase(
         order_id=order_id, transaction_id=transaction_id,
-        payload=str(request_options), line_id=line_id
+        amount=amount, nft_id=nft_id,
+        payment_status="establish the order", line_id=line_id
     )
     payment = crud.payment.create(db=db, obj_in=payment_obj)
-    # return response
+
     return {"web":response["info"]["paymentUrl"]['web'], "app":response["info"]["paymentUrl"]['web']}
     return response["info"]["paymentUrl"]
 
@@ -89,12 +108,16 @@ async def pay_request(
 # Confirm
 @router.get('/confirm')
 async def pay_confirm(
-    transactionId: int = "transactionId",
+    transactionId: int = 123456789,
+    db: Session = Depends(deps.get_db)
 ):
-    CACHE["transaction_id"] = transactionId
+    db_ = dataset.connect(
+        'mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4'
+    )
+    transaction_table = db_['transaction']
+    payment = crud.payment.get_by_transaction(db, transaction_id=transactionId)
     response = line.confirm(
-        transactionId, float(CACHE.get("amount", 1)),
-        CACHE.get("currency", "TWD"))
+        transactionId, float(payment.amount), "TWD")
     check_result = line.check_payment_status(transactionId)
     payment_details = line.payment_details(transaction_id=transactionId)
     response["transaction_id"] = transactionId
@@ -106,7 +129,52 @@ async def pay_confirm(
     )
     response["payment_details"] = payment_details
     if(response["paymentStatusCheckReturnCode"] == '0123'):
-        # return response
-        return "OK"
+        to = crud.user.get_by_lineid(db, lineid=payment.line_id).__dict__['useraddress']
+        payload = {
+            "txid": transactionId,
+            # "contract": "0xe0d9102c88b09369df99b1c126fb2eebc13804f8",
+            "contract": "0x8d5a7d8ca33fd9edca4b871cf5fb2a9cb5091505",
+            "to": to,
+            "uid": crud.nft.get(db, id=payment.nft_id).__dict__['uid'],
+            "value": payment.amount
+        }
+        r = requests.post(baseUrl + "accounts/U9dc55544ecca3a95b170bdf2a30e3691/erc1155/transfer_by_admin",
+                        headers=headers, data=payload)
+        payment_update = schemas.payment.PaymentUpdate(**jsonable_encoder(payment))
+        if r.status_code == 200:
+            title = crud.nft.get(db, id=payment.nft_id).__dict__['title']
+            message = "您的NFT : " + title + ", 已劃轉!"
+            push_text("U9dc55544ecca3a95b170bdf2a30e3691", message)
+            transaction_table.insert({'txid':transactionId,'tfrom':"U9dc55544ecca3a95b170bdf2a30e3691",'to':payment.line_id,'nft':crud.nft.get(db, id=payment.nft_id).__dict__['uid'],'transaction_at':datetime.now()})
+            from_name = settings.line_bot_api.get_profile("U9dc55544ecca3a95b170bdf2a30e3691").as_json_dict()['displayName']
+            try:
+                to_name = settings.line_bot_api.get_profile(payment.line_id).as_json_dict()['displayName']
+            except:
+                to_name = "外部"
+            fr = "您賣給"+ to_name +"的NFT(" + title + "), 已發送,請靜待網路確認!"
+            to_message = "您購買的NFT("+title+"), 已成功,請靜待網路確認!"
+            push_text("U9dc55544ecca3a95b170bdf2a30e3691", fr)
+            try:
+                push_text(payment.line_id, to_message)
+            except:
+                pass
+            payment_update.payment_status = "success"
+            crud.payment.update(db, db_obj=payment, obj_in=payment_update)
+            return "OK"
+        else:
+            # push訊息
+            payment_update.payment_status = "success get payment, but transfer failed, error message is" + r.content
+            crud.payment.update(db, db_obj=payment, obj_in=payment_update)
+            message = str(transactionId) + " 收款成功,轉移失敗, error message is" + r.content
+            to_message = str(transactionId)+ " 收款成功,轉移失敗,請洽客服"
+            try:
+                push_text(payment.line_id, to_message)
+            except:
+                pass
+            push_text("U9dc55544ecca3a95b170bdf2a30e3691", message)
+            return {'msg': "收款成功,轉移失敗,請洽客服"}
     else:
-        return "Not found"
+        payment_update = schemas.payment.PaymentUpdate(**jsonable_encoder(payment))
+        payment_update.payment_status = "cancel"
+        crud.payment.update(db, db_obj=payment, obj_in=payment_update)
+        return "交易取消"

+ 10 - 0
app/core/redis.py

@@ -0,0 +1,10 @@
+from typing import AsyncIterator
+
+from aioredis import create_redis_pool, Redis
+
+
+async def init_redis_pool(host: str, password: str) -> AsyncIterator[Redis]:
+    pool = await create_redis_pool(f"redis://{host}", password=password)
+    yield pool
+    pool.close()
+    await pool.wait_closed()

+ 5 - 5
app/crud/__init__.py

@@ -1,10 +1,10 @@
-# from .crud_item import item
-# from .crud_user import user
-from app.models.payment import Payment
-from app.schemas.payment import PaymentCreate, PaymentUpdate
+
+# from app.models.payment import Payment
+# from app.schemas.payment import PaymentCreate, PaymentUpdate
 from .crud_user import user
 from .crud_nft import nft
+from .crud_payment import payment
 # For a new basic set of CRUD operations you could just do
 from .base import CRUDBase
 
-payment = CRUDBase[Payment, PaymentCreate, PaymentUpdate](Payment)
+# payment = CRUDBase[Payment, PaymentCreate, PaymentUpdate](Payment)

+ 17 - 0
app/crud/crud_payment.py

@@ -0,0 +1,17 @@
+from audioop import add
+from typing import Any, Dict, Optional, Union
+
+from sqlalchemy.orm import Session
+
+from app.core.security import get_password_hash, verify_password
+from app.crud.base import CRUDBase
+from app.models.payment import Payment
+from app.schemas.payment import PaymentBase, PaymentCreate, PaymentUpdate
+
+
+class CRUDPayment(CRUDBase[Payment, PaymentBase, PaymentCreate]):
+    def get_by_transaction(self, db: Session, *, transaction_id: str) -> Optional[Payment]:
+        return db.query(Payment).filter(Payment.transaction_id == transaction_id).first()
+
+
+payment = CRUDPayment(Payment)

+ 4 - 2
app/models/payment.py

@@ -8,6 +8,8 @@ class Payment(Base):
     id = Column(Integer, primary_key=True, nullable=False)
     order_id = Column(String(100), nullable=False)
     transaction_id = Column(String(200), nullable=False)
-    payload = Column(Text(), nullable=False)
-    create_at = Column(String(200), nullable=False, default=datetime.datetime.now)
+    create_time = Column(String(200), nullable=False, default=datetime.datetime.now)
     line_id = Column(String(200), nullable=False)
+    nft_id = Column(Integer)
+    amount = Column(Integer)
+    payment_status = Column(String(255))

+ 1 - 0
app/schemas/line.py

@@ -11,6 +11,7 @@ class TransactionNft(BaseModel):
 class BuyNft(BaseModel):
     nftid: str 
     userid: str
+    amount: int
 
     class Config:
         orm_mode = True

+ 5 - 2
app/schemas/payment.py

@@ -1,4 +1,5 @@
 from datetime import datetime
+from lib2to3.pgen2.token import OP
 from typing import Optional
 from pydantic import BaseModel
 
@@ -8,9 +9,11 @@ class PaymentBase(BaseModel):
     id: Optional[str] = None
     order_id: Optional[str] = None
     transaction_id: Optional[str] = None
-    payload: Optional[str] = None
-    create_at: Optional[datetime] = datetime.now()
+    create_time: Optional[datetime] = datetime.now()
     line_id: Optional[str] = None
+    nft_id: int
+    amount: int
+    payment_status: Optional[str] = None
 
     class Config:
         orm_mode = True