123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- import uvicorn
- import fastapi
- from fastapi.middleware.cors import CORSMiddleware
- from fastapi.responses import HTMLResponse
- from linebot import LineBotApi, WebhookHandler
- from linebot.models import (
- MessageEvent, TextMessage, TextSendMessage, FollowEvent, TemplateSendMessage, ButtonsTemplate, URITemplateAction,
- )
- import dataset
- import requests
- import json
- import qrcode
- # from PIL import Image
- # import base64, io
- from random import randrange
- import models
- import datetime as dt
- app = fastapi.FastAPI()
- app.add_middleware(
- CORSMiddleware,
- allow_origins=['*'],
- allow_credentials=True,
- allow_methods=["*"],
- allow_headers=["*"],
- )
- # bot config
- line_bot_api = LineBotApi("SJT7VPT4RMQFLcS27jQBy3FcC24gtDrkcwJWZ5Xzqesr5T78LOKudHEJzt0k3b2S7n4KPwf27J7DVz2c8NQ4plSaaQylEeB1cYrfejaE/RPG/lCIQBYe4iBTzo26s4i2PcmT89837per/lTyvhVIKAdB04t89/1O/w1cDnyilFU=")
- handler = WebhookHandler("411ae3ef7e766739ed2c2c27b249d010")
- # callback event
- @app.post("/callback")
- async def callback(request: fastapi.Request):
- signature = request.headers['X-Line-Signature']
- body = await request.body()
- handler.handle(body.decode('utf-8'), signature)
- return 'OK'
- # follow event
- @handler.add(FollowEvent)
- def handle_follow(event):
- # get user id when follow
- real_user_id = event.source.user_id
- # db connect and search
- db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
- table = db['users']
- result1 = table.find_one(userid=real_user_id)
- # 都存在db的話
- if result1:
- db.close()
- line_bot_api.reply_message(
- event.reply_token,
- TextSendMessage(text='很高興再見到您!'))
- # 建立全新使用者
- else:
- # create user account api
- url = 'https://nft-api-staging.joyso.io/api/v1/accounts'
- headers = {'Authorization': 'Basic bmZ0OmMxOTEzOWMzYjM3YjdjZWU3ZmY3OTFiZGU3NzdjZWNl'}
- # setup for temp use (unique id)
- rand_num = str(randrange(99999))
- user_id = event.source.user_id + rand_num
- data = 'uid=' + user_id
- r = requests.post(url=url, headers=headers, data=data)
- # extract the account address
- dict_str = json.loads(r.text)
- user_account = dict_str['account']
- user_address = user_account['address']
- # generate qr code from user id
- qr = qrcode.QRCode(
- version=1,
- box_size=10,
- border=5)
- qr.add_data(user_address)
- qr.make(fit=True)
- img_qr = qr.make_image(fill='black', back_color='white')
- filename = "/var/www/ArkCard-Linebot/ArkCard-web/qrcode/" + real_user_id + '.png'
- img_save = img_qr.save(filename)
- # add to db
- data = dict(userid=real_user_id, useraddress=user_address)
- table.insert(data)
- db.close()
- line_bot_api.reply_message(
- event.reply_token,
- TextSendMessage(text='歡迎加入好友'))
- # message handler
- @handler.add(MessageEvent, message=TextMessage)
- def message(event):
- if '我要發送' in event.message.text:
- button_template_message = ButtonsTemplate(
- title=' ',
- text='點擊並打開收藏的NFT,可以選擇想要發送的NFT給對方!',
- actions=[
- URITemplateAction(
- label='打開發送頁',
- uri='https://ark.cards/collect.html?' + event.source.user_id),])
- line_bot_api.reply_message(
- event.reply_token,
- TemplateSendMessage(
- alt_text="Receive",
- template=button_template_message))
- elif '我要接收' in event.message.text:
- button_template_message = ButtonsTemplate(
- title=' ',
- text='點擊並打開接收頁面,即可分享接收地址給對方!',
- actions=[
- URITemplateAction(
- label='打開接收頁',
- uri='https://ark.cards/qr-code.html?' + event.source.user_id),])
- line_bot_api.reply_message(
- event.reply_token,
- TemplateSendMessage(
- alt_text="Receive",
- template=button_template_message))
- elif 'NFT商店' in event.message.text:
- button_template_message = ButtonsTemplate(
- title=' ',
- text='點擊並打開NFT商品頁,就可以購買您所想要的NFT商品哦!',
- actions=[
- URITemplateAction(
- label='打開NFT商品頁',
- uri='https://ark.cards/shop.html?' + event.source.user_id),])
- line_bot_api.reply_message(
- event.reply_token,
- TemplateSendMessage(
- alt_text="Receive",
- template=button_template_message))
- elif 'NFT收藏' in event.message.text:
- button_template_message = ButtonsTemplate(
- title=' ',
- text='點擊並打開收藏的NFT,可以查看收到的NFT!',
- actions=[
- URITemplateAction(
- label='打開收藏頁',
- uri='https://ark.cards/collect.html?' + event.source.user_id), ])
- line_bot_api.reply_message(
- event.reply_token,
- TemplateSendMessage(
- alt_text="Receive",
- template=button_template_message))
- else:
- button_template_message = ButtonsTemplate(
- title=' ',
- text='更多的服務內容,歡迎請上我們的官網!',
- actions=[
- URITemplateAction(
- label='ArkCard的官網',
- uri='https://ark.cards'),])
- line_bot_api.reply_message(
- event.reply_token,
- TemplateSendMessage(
- alt_text="Receive",
- template=button_template_message))
- # nft collection api
- @app.get("/collection/{userid}")
- def collection(userid):
- # 連到ownership表單去找,並回傳json
- # db connect
- db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
- table1 = db['ownership']
- nft = {}
- i = 0
- if not table1.find_one(userid=userid):
- db.close()
- return "error: user don't have any nft"
- else:
- results = db.query("SELECT nftid, amount FROM arkcard.ownership WHERE userid IN (SELECT userid FROM arkcard.ownership WHERE userid = '"+userid+"');")
- for item in results:
- nft[i] = item
- i += 1
- db.close()
- return nft
- # receive handler
- @app.get("/receive/{userid}")
- def receive(userid):
- # 確定要傳送的對象,到user去找到它
- # db connect
- db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
- table = db['users']
- if not table.find_one(userid=userid):
- db.close()
- return "ERROR: User Not Found"
- else:
- result = table.find_one(userid=userid)
- db.close()
- return {"userid": result['userid'], "address": result['address']}
- # send handler
- @app.post("/send")
- async def receive(userModel : models.TransactionNft):
- # 從網頁上選定好商品,在選定好數量後輸入收方地址;將把該商品轉到收方,並存下交易記錄
- # 從ownership找到該userid的擁有人,再把擁有人userid改為收方,並在trans留下記錄
- # db connect
- db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
- table1 = db['users']
- table2 = db['ownership']
- table3 = db['transactions']
- # find the userid from the selected nft
- fromuser = userModel.fromuser
- address = userModel.address
- result1 = table1.find_one(address=address)
- result2 = table1.find_one(userid=fromuser)
- # 例:
- # {
- # "fromuser": "a01",
- # "address": "0x4cd0ea8b1bdb5ab9249d96ccf3d8a0d3ada2bc76",
- # "dic": {"10":"2", "20":"3"}
- # }
- # 第一個為nftid, 第二個為amount,可以同時輸入多組nft給同一人
- the_list = userModel.dic
- fr_token = "from token"
- _hash = "hash"
- # confirm if the user exist
- # 如果沒有這個接受者,回傳錯誤
- if not result1:
- db.close()
- return {'msg': 'user not found'}
- # 確認發送方的nft夠不夠發放
- else:
- for nftid, amount in the_list.items():
- print("nft: "+nftid+",數量:"+ amount)
- # 直接針對取到的值去做確認數量和更新表單,最後再記錄
- # 確認sender的總數
- result3 = db.query('SELECT SUM(amount) AS total FROM arkcard.ownership WHERE userid="' + fromuser + '" AND nftid ="' + nftid + '";')
- # 把總數撈出來,存到total
- for row in result3:
- rows = row
- total = rows['total']
- # 如果總數不夠,就報錯回傳
- if total == None or total < int(amount):
- db.close()
- return {"messge: NFT not enough"}
- # 總數夠,在ownership刪去數量,並再新增ownership一筆
- else:
- # 今天到這,需要找出怎麼扣除總數的方式,目前找到的總數,會更新到資料欄位,導致原本才100個的,會被更新成499個,因為全加到一個
- # 找接收者的userid
- to_user = result1['userid']
- old_address = result2['address']
- print(total)
- new_amount = total - int(amount)
- # 更新原user總數
- result4 = db.query('DELETE FROM arkcard.ownership WHERE userid="' + fromuser + '" AND nftid ="' + nftid + '";')
- result5 = db.query('UPDATE arkcard.ownership SET amount = amount - "' + amount + '" WHERE userid = "' + fromuser + '" AND nftid = "' + nftid + '" LIMIT 1;')
- new_data1 = dict(userid=fromuser, address=old_address, nftid=nftid, amount=new_amount)
- table2.insert(new_data1)
- # 增加新user數量
- new_data2 = dict(userid=to_user, address=address, nftid=nftid, amount=int(amount))
- table2.insert(new_data2)
- # 在transactions記錄from和to, 以及時間等等
- now = dt.datetime.now()
- trans_data = dict(to_token=address, time=now, amount=int(amount), userid=fromuser, from_token=fr_token, hash=_hash)
- table3.insert(trans_data)
- db.close()
- return {"messge: NFT 夠"}
- # shop handler
- @app.get("/shop")
- def shop():
- # 為了顯示正確的nft網頁和數量,直接顯示nft表出來
- # db connect
- db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
- result1 = db.query('SELECT nftid, launched, amount, type, title, context FROM arkcard.nft WHERE launched="y" AND nftid NOT IN(SELECT nftid FROM arkcard.nft_to_event);')
- nfts = {}
- i = 0
- for row in result1:
- nfts[i] = row
- i += 1
- return nfts
- db.close()
- @app.post("/buy")
- async def buy(userModel : models.BuyNft):
- # db connect
- db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
- table1 = db['users']
- table2 = db['ownership']
- table3 = db['nft']
- table4 = db['transactions']
- shops = "shop"
- hash = "hash"
- # input
- the_list = userModel.dic
- address = userModel.address
- # 例:
- # {
- # "address": "d04",
- # "dic": {"1":"2","2":"3"}
- # }
- result1 = table1.find_one(address=address)
- # 找不到該使用者就回報錯誤
- if not result1:
- db.close()
- return "該用戶不存在!如果有疑問,請洽網站的服務信箱!"
- else:
- for nftid, amount in the_list.items():
- # 先user找到該使用者的userid留著備用
- userid = result1['userid']
- # 更新到ownership
- owner_data = [dict(userid=userid, address=address, nftid=nftid, amount=int(amount))]
- table2.insert_many(owner_data)
- # 更新nft數量
- result3 = table3.find_one(nftid=nftid)
- nft_total = result3['amount']
- total = int(nft_total) - int(amount)
- nft_data = dict(nftid=nftid, amount=int(total))
- table3.update(nft_data, ['nftid'])
- # 最後再來處理transactions
- now = dt.datetime.now()
- trans_data = dict(to_token=address, time=now, amount=int(amount), userid=userid, from_token=shops, hash=hash)
- table4.insert(trans_data)
- db.close()
- return "您已購買成功!"
- @app.post("/event")
- async def nftdrops(userModel : models.NftDrops):
- # db connect
- db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
- table1 = db['nft_drop_list']
- # input
- userid = userModel.userid
- email = userModel.email
- the_current_event = eventPeriod()
- if the_current_event == 0:
- return "目前沒有任何進行中的活動"
- else:
- # 再針對有上架的 event 填寫客戶到 nftdroplist
- now = dt.datetime.now()
- result1 = table1.find_one(userid=userid)
- if not result1:
- for key, item in the_current_event.items():
- table1.insert(dict(eventid=item, userid=userid, email=email, time=now))
- db.close()
- return "完成加入"
- else:
- db.close()
- return "該資料已存在"
- @app.post("/eventPeriod")
- def eventPeriod():
- # db connect
- db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
- # 設定event始終期間,與上架與否
- table3 = db['event']
- now = dt.datetime.now()
- # 先去找 event 表,確認在期間之內
- result = db.query("SELECT * FROM arkcard.event WHERE start < NOW() and NOW() < end and launched='yes';")
- rows = {}
- i = 0
- for row in result:
- rows[i] = row['eventid']
- i += 1
- return rows
- db.close()
- if __name__ == '__main__':
- uvicorn.run("main:app", host="0.0.0.0", port=8228, reload=True,ssl_context=('/etc/letsencrypt/live/ark.cards/fullchain.pem', '/etc/letsencrypt/live/ark.cards/privkey.pem'))
|