main.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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. app = fastapi.FastAPI()
  18. app.add_middleware(
  19. CORSMiddleware,
  20. allow_origins=['*'],
  21. allow_credentials=True,
  22. allow_methods=["*"],
  23. allow_headers=["*"],
  24. )
  25. # bot config
  26. line_bot_api = LineBotApi("SJT7VPT4RMQFLcS27jQBy3FcC24gtDrkcwJWZ5Xzqesr5T78LOKudHEJzt0k3b2S7n4KPwf27J7DVz2c8NQ4plSaaQylEeB1cYrfejaE/RPG/lCIQBYe4iBTzo26s4i2PcmT89837per/lTyvhVIKAdB04t89/1O/w1cDnyilFU=")
  27. handler = WebhookHandler("411ae3ef7e766739ed2c2c27b249d010")
  28. # callback event
  29. @app.post("/callback")
  30. async def callback(request: fastapi.Request):
  31. signature = request.headers['X-Line-Signature']
  32. body = await request.body()
  33. handler.handle(body.decode('utf-8'), signature)
  34. return 'OK'
  35. # follow event
  36. @handler.add(FollowEvent)
  37. def handle_follow(event):
  38. # get user id when follow
  39. real_user_id = event.source.user_id
  40. # db connect and search
  41. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
  42. table = db['users']
  43. table2 = db['nft']
  44. result1 = table.find_one(userid=real_user_id)
  45. result2 = table2.find_one(userid=real_user_id)
  46. # 都存在db的話
  47. if result1 and result2:
  48. db.close()
  49. line_bot_api.reply_message(
  50. event.reply_token,
  51. TextSendMessage(text='很高興再見到您!'))
  52. # 只存在user,新增nft給他
  53. elif result1 and not result2:
  54. # prepare nft for new follower
  55. result3 = table2.find_one(userid=None) or table2.find_one(userid='')
  56. result3['userid'] = real_user_id
  57. table2.update(dict(result3), ['id'])
  58. db.close()
  59. line_bot_api.reply_message(
  60. event.reply_token,
  61. TextSendMessage(text='很高興再見到您!'))
  62. # 只存在nft,新加到user
  63. elif result2 and not result1:
  64. # create user account api
  65. url = 'https://nft-api-staging.joyso.io/api/v1/accounts'
  66. headers = {'Authorization': 'Basic bmZ0OmMxOTEzOWMzYjM3YjdjZWU3ZmY3OTFiZGU3NzdjZWNl'}
  67. # setup for temp use (unique id)
  68. rand_num = str(randrange(99999))
  69. user_id = event.source.user_id + rand_num
  70. data = 'uid=' + user_id
  71. r = requests.post(url=url, headers=headers, data=data)
  72. # extract the account address
  73. dict_str = json.loads(r.text)
  74. user_account = dict_str['account']
  75. user_address = user_account['address']
  76. # generate qr code from user id
  77. qr = qrcode.QRCode(
  78. version=1,
  79. box_size=10,
  80. border=5)
  81. qr.add_data(user_address)
  82. qr.make(fit=True)
  83. img_qr = qr.make_image(fill='black', back_color='white')
  84. filename = "/var/www/ArkCard-Linebot/ArkCard-web/qrcode/" + real_user_id + '.png'
  85. img_save = img_qr.save(filename)
  86. # add to db
  87. data = dict(userid=real_user_id, useraddress=user_address)
  88. table.insert(data)
  89. db.close()
  90. line_bot_api.reply_message(
  91. event.reply_token,
  92. TextSendMessage(text='很高興再見到您!'))
  93. # 都不存在,兩種都新建
  94. else:
  95. # create user account api
  96. url = 'https://nft-api-staging.joyso.io/api/v1/accounts'
  97. headers = {'Authorization': 'Basic bmZ0OmMxOTEzOWMzYjM3YjdjZWU3ZmY3OTFiZGU3NzdjZWNl'}
  98. # setup for temp use (unique id)
  99. rand_num = str(randrange(99999))
  100. user_id = event.source.user_id + rand_num
  101. data = 'uid=' + user_id
  102. r = requests.post(url=url, headers=headers, data=data)
  103. # extract the account address
  104. dict_str = json.loads(r.text)
  105. user_account = dict_str['account']
  106. user_address = user_account['address']
  107. # generate qr code from user id
  108. qr = qrcode.QRCode(
  109. version=1,
  110. box_size=10,
  111. border=5)
  112. qr.add_data(user_address)
  113. qr.make(fit=True)
  114. img_qr = qr.make_image(fill='black', back_color='white')
  115. filename = "/var/www/ArkCard-Linebot/ArkCard-web/qrcode/" + real_user_id + '.png'
  116. img_save = img_qr.save(filename)
  117. # add to db
  118. data = dict(userid=real_user_id, useraddress=user_address)
  119. table.insert(data)
  120. # prepare nft for new follower
  121. result3 = table2.find_one(userid=None) or table2.find_one(userid='')
  122. result3['userid'] = real_user_id
  123. table2.update(dict(result3), ['id'])
  124. db.close()
  125. line_bot_api.reply_message(
  126. event.reply_token,
  127. TextSendMessage(text='歡迎加入好友'))
  128. # message handler
  129. @handler.add(MessageEvent, message=TextMessage)
  130. def message(event):
  131. if '我要發送' in event.message.text:
  132. button_template_message = ButtonsTemplate(
  133. title=' ',
  134. text='點擊並打開收藏的NFT,可以選擇想要發送的NFT給對方!',
  135. actions=[
  136. URITemplateAction(
  137. label='打開發送頁',
  138. uri='https://ark.cards/collect.html?' + event.source.user_id),])
  139. line_bot_api.reply_message(
  140. event.reply_token,
  141. TemplateSendMessage(
  142. alt_text="Receive",
  143. template=button_template_message))
  144. elif '我要接收' in event.message.text:
  145. button_template_message = ButtonsTemplate(
  146. title=' ',
  147. text='點擊並打開接收頁面,即可分享接收地址給對方!',
  148. actions=[
  149. URITemplateAction(
  150. label='打開接收頁',
  151. uri='https://ark.cards/qr-code.html?' + event.source.user_id),])
  152. line_bot_api.reply_message(
  153. event.reply_token,
  154. TemplateSendMessage(
  155. alt_text="Receive",
  156. template=button_template_message))
  157. elif 'NFT商店' in event.message.text:
  158. button_template_message = ButtonsTemplate(
  159. title=' ',
  160. text='點擊並打開NFT商品頁,就可以購買您所想要的NFT商品哦!',
  161. actions=[
  162. URITemplateAction(
  163. label='打開NFT商品頁',
  164. uri='https://ark.cards/shop.html?' + event.source.user_id),])
  165. line_bot_api.reply_message(
  166. event.reply_token,
  167. TemplateSendMessage(
  168. alt_text="Receive",
  169. template=button_template_message))
  170. elif 'NFT收藏' in event.message.text:
  171. button_template_message = ButtonsTemplate(
  172. title=' ',
  173. text='點擊並打開收藏的NFT,可以查看收到的NFT!',
  174. actions=[
  175. URITemplateAction(
  176. label='打開收藏頁',
  177. uri='https://ark.cards/collect.html?' + event.source.user_id), ])
  178. line_bot_api.reply_message(
  179. event.reply_token,
  180. TemplateSendMessage(
  181. alt_text="Receive",
  182. template=button_template_message))
  183. else:
  184. button_template_message = ButtonsTemplate(
  185. title=' ',
  186. text='更多的服務內容,歡迎請上我們的官網!',
  187. actions=[
  188. URITemplateAction(
  189. label='ArkCard的官網',
  190. uri='https://ark.cards'),])
  191. line_bot_api.reply_message(
  192. event.reply_token,
  193. TemplateSendMessage(
  194. alt_text="Receive",
  195. template=button_template_message))
  196. # nft collection api
  197. @app.get("/collection/{userid}")
  198. def collection(userid):
  199. # db connect
  200. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
  201. table2 = db['nft']
  202. if not table2.find_one(userid=userid):
  203. db.close()
  204. return "您尚未擁有NFT商品,歡迎前往NFT商店購買!"
  205. else:
  206. xname = userid
  207. sql = 'SELECT a.* FROM nft a INNER JOIN (SELECT userid FROM users WHERE userid="' + xname + '") b ON b.userid = a.userid'
  208. result = db.query(sql)
  209. rows = {}
  210. i = 0
  211. for row in result:
  212. rows[i] = row
  213. i += 1
  214. return rows
  215. db.close()
  216. # receive handler
  217. @app.get("/receive/{userid}")
  218. def receive(userid):
  219. # db connect
  220. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
  221. table = db['users']
  222. table.find_one(userid=userid)
  223. if not table.find_one(userid=userid):
  224. db.close()
  225. return "ERROR: User Not Found"
  226. else:
  227. result = table.find_one(userid=userid)
  228. db.close()
  229. return {"userid": result['userid'], "base": result['base'], "useraddress": result['useraddress']}
  230. # send handler
  231. @app.post("/send")
  232. async def receive(userModel : models.TransactionNft):
  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. address = userModel.address
  239. result = ""
  240. if not table2.find_one(id=nftid):
  241. db.close()
  242. print("error: nft not found")
  243. return {'msg': 'nft not found'}
  244. else:
  245. statement = 'SELECT userid FROM users WHERE useraddress ="'+address+'"'
  246. for row in db.query(statement):
  247. result = row['userid']
  248. user_obj = table2.find_one(id=nftid)
  249. user_obj['userid'] = result
  250. table2.update(dict(user_obj), ['id'])
  251. db.close()
  252. return {'msg': 'OK'}
  253. # shop handler
  254. @app.get("/shop/{userid}")
  255. def shop(userid):
  256. # db connect
  257. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
  258. sql = 'SELECT * FROM arkcard.nft WHERE userid IS NULL OR userid="" LIMIT 5'
  259. result = db.query(sql)
  260. rows = {}
  261. i = 0
  262. for row in result:
  263. rows[i] = row
  264. i += 1
  265. return rows
  266. db.close()
  267. # market
  268. @app.get("/market")
  269. def market():
  270. # db connect
  271. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
  272. sql = 'SELECT * FROM arkcard.nft WHERE userid IS NULL OR userid="" LIMIT 10'
  273. result = db.query(sql)
  274. rows = {}
  275. i = 0
  276. for row in result:
  277. rows[i] = row
  278. i += 1
  279. return rows
  280. db.close()
  281. @app.post("/buy")
  282. async def buy(userModel : models.BuyNft):
  283. # db connect
  284. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/arkcard?charset=utf8mb4')
  285. table2 = db['nft']
  286. # input
  287. nftid = userModel.nftid
  288. userid = userModel.userid
  289. if not table2.find_one(id=nftid):
  290. db.close()
  291. print("error: nft not found")
  292. return "該NFT商品不存在!如果有疑問,請洽網站的服務信箱!"
  293. else:
  294. user_obj = table2.find_one(id=nftid)
  295. user_obj['userid'] = userid
  296. table2.update(dict(user_obj), ['id'])
  297. db.close()
  298. return "您已購買成功!"
  299. # @app.post("/callevent")
  300. # async def callevent(userModel: models.callBack):
  301. # """
  302. # 事件會用application/json和POST方式打到指定位址, 內容基本包含
  303. # {
  304. # "type": "xxx", // 事件類型, 字串
  305. # "data": {} // 事件內容資料
  306. # }
  307. # """
  308. # str1 = userModel.type
  309. # dict1 = userModel.data
  310. # result = str1, dict1
  311. # return result
  312. if __name__ == '__main__':
  313. 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'))