main.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. import uvicorn
  2. import fastapi
  3. from fastapi.middleware.cors import CORSMiddleware
  4. from fastapi.responses import HTMLResponse
  5. from linebot import LineBotApi, WebhookHandler
  6. from linebot.models import (
  7. MessageEvent, TextMessage, TextSendMessage, FollowEvent, TemplateSendMessage, ButtonsTemplate, URITemplateAction,
  8. )
  9. import dataset
  10. import requests
  11. import json
  12. import qrcode
  13. from PIL import Image
  14. import base64, io
  15. from random import randrange
  16. import models
  17. import time
  18. time = time.ctime()
  19. app = fastapi.FastAPI()
  20. app.add_middleware(
  21. CORSMiddleware,
  22. allow_origins=['*'],
  23. allow_credentials=True,
  24. allow_methods=["*"],
  25. allow_headers=["*"],
  26. )
  27. # bot config
  28. line_bot_api = LineBotApi("SJT7VPT4RMQFLcS27jQBy3FcC24gtDrkcwJWZ5Xzqesr5T78LOKudHEJzt0k3b2S7n4KPwf27J7DVz2c8NQ4plSaaQylEeB1cYrfejaE/RPG/lCIQBYe4iBTzo26s4i2PcmT89837per/lTyvhVIKAdB04t89/1O/w1cDnyilFU=")
  29. handler = WebhookHandler("411ae3ef7e766739ed2c2c27b249d010")
  30. # callback event
  31. @app.post("/callback")
  32. async def callback(request: fastapi.Request):
  33. signature = request.headers['X-Line-Signature']
  34. body = await request.body()
  35. handler.handle(body.decode('utf-8'), signature)
  36. return 'OK'
  37. # follow event
  38. @handler.add(FollowEvent)
  39. def handle_follow(event):
  40. # get user id when follow
  41. real_user_id = event.source.user_id
  42. # db connect and search
  43. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
  44. table = db['users']
  45. result1 = table.find_one(userid=real_user_id)
  46. # 都存在db的話
  47. if result1:
  48. db.close()
  49. line_bot_api.reply_message(
  50. event.reply_token,
  51. TextSendMessage(text='很高興再見到您!'))
  52. # 建立全新使用者
  53. else:
  54. # create user account api
  55. url = 'https://nft-api-staging.joyso.io/api/v1/accounts'
  56. headers = {'Authorization': 'Basic bmZ0OmMxOTEzOWMzYjM3YjdjZWU3ZmY3OTFiZGU3NzdjZWNl'}
  57. # setup for temp use (unique id)
  58. rand_num = str(randrange(99999))
  59. user_id = event.source.user_id + rand_num
  60. data = 'uid=' + user_id
  61. r = requests.post(url=url, headers=headers, data=data)
  62. # extract the account address
  63. dict_str = json.loads(r.text)
  64. user_account = dict_str['account']
  65. user_address = user_account['address']
  66. # generate qr code from user id
  67. qr = qrcode.QRCode(
  68. version=1,
  69. box_size=10,
  70. border=5)
  71. qr.add_data(user_address)
  72. qr.make(fit=True)
  73. img_qr = qr.make_image(fill='black', back_color='white')
  74. filename = "/var/www/ArkCard-Linebot/ArkCard-web/qrcode/" + real_user_id + '.png'
  75. img_save = img_qr.save(filename)
  76. # add to db
  77. data = dict(userid=real_user_id, useraddress=user_address)
  78. table.insert(data)
  79. db.close()
  80. line_bot_api.reply_message(
  81. event.reply_token,
  82. TextSendMessage(text='歡迎加入好友'))
  83. db.close()
  84. # message handler
  85. @handler.add(MessageEvent, message=TextMessage)
  86. def message(event):
  87. if '我要發送' in event.message.text:
  88. button_template_message = ButtonsTemplate(
  89. title=' ',
  90. text='點擊並打開收藏的NFT,可以選擇想要發送的NFT給對方!',
  91. actions=[
  92. URITemplateAction(
  93. label='打開發送頁',
  94. uri='https://ark.cards/collect.html?' + event.source.user_id),])
  95. line_bot_api.reply_message(
  96. event.reply_token,
  97. TemplateSendMessage(
  98. alt_text="Receive",
  99. template=button_template_message))
  100. elif '我要接收' in event.message.text:
  101. button_template_message = ButtonsTemplate(
  102. title=' ',
  103. text='點擊並打開接收頁面,即可分享接收地址給對方!',
  104. actions=[
  105. URITemplateAction(
  106. label='打開接收頁',
  107. uri='https://ark.cards/qr-code.html?' + event.source.user_id),])
  108. line_bot_api.reply_message(
  109. event.reply_token,
  110. TemplateSendMessage(
  111. alt_text="Receive",
  112. template=button_template_message))
  113. elif 'NFT商店' in event.message.text:
  114. button_template_message = ButtonsTemplate(
  115. title=' ',
  116. text='點擊並打開NFT商品頁,就可以購買您所想要的NFT商品哦!',
  117. actions=[
  118. URITemplateAction(
  119. label='打開NFT商品頁',
  120. uri='https://ark.cards/shop.html?' + event.source.user_id),])
  121. line_bot_api.reply_message(
  122. event.reply_token,
  123. TemplateSendMessage(
  124. alt_text="Receive",
  125. template=button_template_message))
  126. elif 'NFT收藏' in event.message.text:
  127. button_template_message = ButtonsTemplate(
  128. title=' ',
  129. text='點擊並打開收藏的NFT,可以查看收到的NFT!',
  130. actions=[
  131. URITemplateAction(
  132. label='打開收藏頁',
  133. uri='https://ark.cards/collect.html?' + event.source.user_id), ])
  134. line_bot_api.reply_message(
  135. event.reply_token,
  136. TemplateSendMessage(
  137. alt_text="Receive",
  138. template=button_template_message))
  139. else:
  140. button_template_message = ButtonsTemplate(
  141. title=' ',
  142. text='更多的服務內容,歡迎請上我們的官網!',
  143. actions=[
  144. URITemplateAction(
  145. label='ArkCard的官網',
  146. uri='https://ark.cards'),])
  147. line_bot_api.reply_message(
  148. event.reply_token,
  149. TemplateSendMessage(
  150. alt_text="Receive",
  151. template=button_template_message))
  152. # nft collection api
  153. @app.get("/collection/{userid}")
  154. def collection(userid):
  155. # db connect
  156. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
  157. table3 = db['nftdrops']
  158. table2 = db['nft']
  159. nftdrops = {}
  160. nft = {}
  161. nfts_all = {}
  162. i = 0
  163. if not table3.find_one(userid=userid) and not table2.find_one(userid=userid):
  164. db.close()
  165. return "error: user don't have any nft"
  166. else:
  167. results1 = table3.find(userid=userid)
  168. for item in results1:
  169. nftdrops[i] = item
  170. i += 1
  171. results2 = table2.find(userid=userid)
  172. for item in results2:
  173. nft[i] = item
  174. i += 1
  175. nfts_all[0] = nftdrops
  176. nfts_all[1] = nft
  177. return nfts_all
  178. db.close()
  179. db.close()
  180. # receive handler
  181. @app.get("/receive/{userid}")
  182. def receive(userid):
  183. # db connect
  184. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
  185. table = db['users']
  186. table.find_one(userid=userid)
  187. if not table.find_one(userid=userid):
  188. db.close()
  189. return "ERROR: User Not Found"
  190. else:
  191. result = table.find_one(userid=userid)
  192. db.close()
  193. return {"userid": result['userid'], "base": result['base'], "useraddress": result['useraddress']}
  194. # send handler
  195. @app.post("/send")
  196. async def receive(userModel : models.TransactionNft):
  197. # db connect
  198. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
  199. table2 = db['nft']
  200. # input
  201. nftid = userModel.nftid
  202. address = userModel.address
  203. result = ""
  204. if not table2.find_one(id=nftid):
  205. db.close()
  206. print("error: nft not found")
  207. return {'msg': 'nft not found'}
  208. else:
  209. statement = 'SELECT userid FROM users WHERE useraddress ="'+address+'"'
  210. for row in db.query(statement):
  211. result = row['userid']
  212. user_obj = table2.find_one(id=nftid)
  213. user_obj['userid'] = result
  214. table2.update(dict(user_obj), ['id'])
  215. db.close()
  216. return {'msg': 'OK'}
  217. # shop handler
  218. @app.get("/shop/{userid}")
  219. def shop(userid):
  220. # db connect
  221. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
  222. sql = 'SELECT * FROM arkcard.nft WHERE userid IS NULL OR userid="" LIMIT 5'
  223. result = db.query(sql)
  224. rows = {}
  225. i = 0
  226. for row in result:
  227. rows[i] = row
  228. i += 1
  229. return rows
  230. db.close()
  231. @app.post("/buy")
  232. async def buy(userModel : models.BuyNft):
  233. # db connect
  234. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
  235. table2 = db['nft']
  236. # input
  237. nftid = userModel.nftid
  238. userid = userModel.userid
  239. if not table2.find_one(id=nftid):
  240. db.close()
  241. print("error: nft not found")
  242. return "該NFT商品不存在!如果有疑問,請洽網站的服務信箱!"
  243. else:
  244. user_obj = table2.find_one(id=nftid)
  245. user_obj['userid'] = userid
  246. table2.update(dict(user_obj), ['id'])
  247. db.close()
  248. return "您已購買成功!"
  249. @app.post("/event")
  250. async def nftdrops(userModel : models.NftDrops):
  251. # db connect
  252. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
  253. table3 = db['nftdrops']
  254. # input對應
  255. userid = userModel.userid
  256. email = userModel.email
  257. eventid = '1'
  258. nftid = '101'
  259. # 如果userid不在db, 寫入到一個空值nft
  260. if not table3.find_one(userid=userid):
  261. # 新增資料
  262. table3.insert(dict(eventid=eventid, nftid=nftid, userid=userid, email=email, time=time))
  263. db.close()
  264. return "新增成功"
  265. # 如果userid存在,回傳通知
  266. else:
  267. db.close()
  268. return "已有資料"
  269. if __name__ == '__main__':
  270. 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'))