views.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. # 主業務邏輯中的視圖和路由的定義
  2. import os
  3. import datetime
  4. from flask import render_template, request, session, Response, url_for
  5. # 導入藍圖程序,用於構建路由
  6. from werkzeug.utils import redirect, secure_filename
  7. from . import main
  8. from manage import mqtt
  9. # 導入db,用於操作數據庫
  10. from manage import db, app
  11. # 導入實體類,用於操作數據庫
  12. from ..models import *
  13. import json
  14. from datetime import datetime as dt
  15. from sqlalchemy import text
  16. import socket
  17. import pickle
  18. import cv2
  19. import numpy as np
  20. import math
  21. import threading
  22. import time
  23. from flask_mqtt import Mqtt
  24. import requests
  25. import re
  26. import copy
  27. from selenium import webdriver
  28. from selenium.webdriver.support.ui import Select
  29. from bs4 import BeautifulSoup
  30. from time import sleep as sl
  31. from app import ALLOWED_EXTENSIONS
  32. import geocoder
  33. # 主頁的訪問路徑
  34. @main.route('/')
  35. def main_index():
  36. # 獲取登入信息
  37. if 'id' in session and 'uname' in session and 'status' in session:
  38. username = session['uname']
  39. if session['status'] == 1:
  40. return redirect('/purchase')
  41. elif session['status'] == 2:
  42. return redirect('/register_number')
  43. else:
  44. return render_template('index.html')
  45. # 登入頁面的訪問路徑
  46. @main.route('/login', methods=['GET', 'POST'])
  47. def login_views():
  48. if request.method == 'GET':
  49. if 'id' in session and 'uname' in session and 'status' in session:
  50. return redirect('/')
  51. else:
  52. return render_template('sign_in.html')
  53. else:
  54. # 接收前端傳過來的資料
  55. username = request.form['username']
  56. password = request.form['password']
  57. # 使用接收的用戶和密碼到資料庫中查詢
  58. user = User.query.filter_by(username=username, password=password).first()
  59. # 如果用戶存在,將信息保存置session並重定向回首頁,否則回登入頁
  60. if user:
  61. resp = redirect('/')
  62. # 判斷是否有記住密碼
  63. if 'rem' in request.form:
  64. sn = str(user.sn)
  65. max_age = 60 * 60 * 24 * 365
  66. resp.set_cookie("username", username, max_age=max_age)
  67. resp.set_cookie("sn", sn, max_age=max_age)
  68. session['uname'] = user.username
  69. session['id'] = user.sn
  70. session['status'] = user.status
  71. return resp
  72. else:
  73. errMsg = "Wrong login or password"
  74. return render_template('sign_in.html', errMsg=errMsg)
  75. # 註冊頁面的訪問路徑
  76. @main.route('/register', methods=['POST', "GET"])
  77. def register_views():
  78. if request.method == 'GET':
  79. return render_template('registration.html')
  80. else:
  81. # 獲取文本框的值並賦值給user實體對象
  82. user = User()
  83. user.firstname = request.form['firstname']
  84. user.lastname = request.form['lastname']
  85. user.mail = request.form['email']
  86. user.phone = request.form['phone']
  87. user.username = request.form['username']
  88. user.password = request.form['password']
  89. user.status = 1
  90. user.isActive = True
  91. # 將數據保存進資料庫 - 註冊
  92. db.session.add(user)
  93. # 手動提交,目的是為了獲取提交後的user的id
  94. db.session.commit()
  95. # 當user成功插入進資料庫之後,程序會自動將所有信息取出來在賦值給user
  96. # 完成登入的操作
  97. user = User.query.filter_by(username=user.username).first()
  98. session['id'] = user.sn
  99. session['uname'] = user.username
  100. session['status'] = user.status
  101. return redirect('/purchase')
  102. #登入重設密碼的頁面
  103. @main.route('/reset_password', methods=['POST', 'GET'])
  104. def reset_password_views():
  105. if request.method == 'GET':
  106. if 'mail' in session:
  107. del session['mail']
  108. return render_template('reset_pwd1.html')
  109. else:
  110. #如果有id在session裡,代表從reset_pwd2過來的
  111. if "mail" in session:
  112. new_pwd = request.form['new_pwd']
  113. confirm_pwd = request.form['confirm_pwd']
  114. #判斷密碼是否一致
  115. if new_pwd == confirm_pwd:
  116. mail = session['mail']
  117. user = User.query.filter_by(mail=mail).first()
  118. user.password = new_pwd
  119. db.session.add(user)
  120. del session['mail']
  121. #修改完後回登入頁
  122. return redirect('/login')
  123. else:
  124. errMsg = "Passwords does not match"
  125. return render_template('reset_pwd2.html', errMsg=errMsg)
  126. email = request.form['email']
  127. user = User.query.filter_by(mail=email).first()
  128. if user:
  129. session['mail'] = user.mail
  130. return render_template('reset_pwd2.html')
  131. else:
  132. errMsg = "Wrong email.Please try again"
  133. return render_template('reset_pwd1.html', errMsg=errMsg)
  134. #驗證email訪問路徑
  135. @main.route('/check_email')
  136. def check_email_views():
  137. email = request.args['email']
  138. user = User.query.filter_by(mail=email).first()
  139. if user:
  140. result = {"errMsg":" "}
  141. else:
  142. result = {"pass":" "}
  143. return json.dumps(result)
  144. #驗證username訪問路徑
  145. @main.route('/check_username')
  146. def check_username_views():
  147. username = request.args['username']
  148. user = User.query.filter_by(username=username).first()
  149. if user:
  150. result = {"errMsg":" "}
  151. else:
  152. result = {"pass":" "}
  153. return json.dumps(result)
  154. #購買頁面的訪問路徑
  155. @main.route('/purchase', methods=['POST', 'GET'])
  156. def purchase_views():
  157. username = session['uname']
  158. if request.method == 'GET':
  159. return render_template('purchase.html', params=locals())
  160. else:
  161. print(request.form)
  162. purchase_info = PurchaseInfo()
  163. purchase_info.loc_length = request.form['length']
  164. purchase_info.loc_width = request.form['width']
  165. purchase_info.location = request.form['location']
  166. purchase_info.monitor_num = request.form['monitor_num']
  167. purchase_info.connect = request.form['connection']
  168. purchase_info.user_id = session['id']
  169. purchase_info.datetime = dt.now()
  170. db.session.add(purchase_info)
  171. db.session.commit()
  172. return redirect('/monitor')
  173. #監控功能頁面的訪問路徑
  174. @main.route('/monitor', methods=['POST', 'GET'])
  175. def monitor_views():
  176. username = session['uname']
  177. purchase_info = PurchaseInfo.query.filter_by(user_id=session['id']).first()
  178. monitor_num = purchase_info.monitor_num
  179. if request.method == 'GET':
  180. return render_template('monitor.html', params=locals())
  181. else:
  182. print(request.form)
  183. D = {}
  184. for i in range(1, monitor_num + 1):
  185. d = {}
  186. for monitor in request.form.getlist('features' + str(i)):
  187. d[monitor] = []
  188. D['node' + str(i)] = d
  189. session['node_info1'] = D
  190. # node_info = NodeInfo()
  191. # node_info.node_info = str(D)
  192. # node_info.purchase_id = purchase_info.sn
  193. # db.session.add(node_info)
  194. # db.session.commit()
  195. return redirect('/module')
  196. #模組頁面的訪問路徑
  197. @main.route('/module', methods=['POST', 'GET'])
  198. def module_views():
  199. username = session['uname']
  200. user = User.query.filter_by(username=username).first()
  201. purchase_id = user.purchase_info.sn
  202. # node_info = NodeInfo.query.filter_by(purchase_id=purchase_id).first()
  203. # node_info = node_info.node_info
  204. if request.method == 'GET':
  205. #將字串變成字典(eval函數:用来执行一个字符串表达式,并返回表达式的值)
  206. # node_info = eval(node_info)
  207. node_info = session['node_info1']
  208. print(node_info)
  209. D = {}
  210. for node in node_info:
  211. l = []
  212. for monitor in node_info[node]:
  213. l.append(monitor)
  214. D[node] = l
  215. sort_L = []
  216. #從node1開始往後按順序排
  217. for i in range(1, len(D) + 1):
  218. sort_L.append(D['node' + str(i)])
  219. sensors = SensorList.query.all()
  220. sensor_list = []
  221. for sensor in sensors:
  222. sensor_list.append(sensor.toDict())
  223. return render_template('module.html', params=locals())
  224. else:
  225. monitor_num = user.purchase_info.monitor_num
  226. D = session['node_info1']
  227. #深拷貝區分session['node_info1']與session['node_info2']
  228. A = copy.deepcopy(D)
  229. for i in range(1, monitor_num + 1):
  230. try:
  231. for module in request.form.getlist('weather_module' + str(i)):
  232. A['node' + str(i)]['weather'].append(module)
  233. except Exception as e:
  234. pass
  235. try:
  236. for module in request.form.getlist('irrigation_module' + str(i)):
  237. A['node' + str(i)]['irrigation'].append(module)
  238. except Exception as e:
  239. pass
  240. try:
  241. for module in request.form.getlist('water_module' + str(i)):
  242. A['node' + str(i)]['water'].append(module)
  243. except Exception as e:
  244. pass
  245. session['node_info2'] = A
  246. return redirect('/list')
  247. #清單頁面的訪問路徑
  248. @main.route('/list', methods=['POST', 'GET'])
  249. def list_views():
  250. username = session['uname']
  251. purchase_info = PurchaseInfo.query.filter_by(user_id=session['id']).first()
  252. D = session['node_info2']
  253. if request.method == 'GET':
  254. sort_L = []
  255. for i in range(1, len(D) + 1):
  256. sort_L.append(json.dumps(D['node' + str(i)]))
  257. sensors = SensorList.query.all()
  258. sensor_list = []
  259. for sensor in sensors:
  260. sensor_list.append(sensor.toDict())
  261. return render_template('list.html', params=locals())
  262. else:
  263. user = User.query.filter_by(username=username).first()
  264. user.status = 2
  265. session['status'] = user.status
  266. print(session['node_info2'])
  267. node_info = NodeInfo()
  268. node_info.node_info = str(session['node_info2'])
  269. node_info.user_id = session['id']
  270. db.session.add(node_info)
  271. db.session.add(user)
  272. db.session.commit()
  273. return redirect('/register_number')
  274. #過濾前端傳過來文件副檔名函數
  275. def allowed_file(filename):
  276. return '.' in filename and \
  277. filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
  278. #登錄序號頁面1的訪問路徑
  279. @main.route('/register_number', methods=['POST', 'GET'])
  280. def register_number_views():
  281. username = session['uname']
  282. purchase_info = PurchaseInfo.query.filter_by(user_id=session['id']).first()
  283. node_info = NodeInfo.query.filter_by(user_id=session['id']).first()
  284. D = eval(node_info.node_info)
  285. if request.method == 'GET':
  286. sort_L = []
  287. for i in range(1, len(D) + 1):
  288. sort_L.append(json.dumps(D['node' + str(i)]))
  289. sensors = SensorList.query.all()
  290. sensor_list = []
  291. for sensor in sensors:
  292. sensor_list.append(sensor.toDict())
  293. return render_template('register_number.html', params=locals())
  294. else:
  295. #使用geocoder庫找經緯度
  296. def get_coordinate(addr):
  297. g = geocoder.arcgis(u"" + addr)
  298. lat, lng = g.latlng
  299. return lat, lng
  300. #使用Geocoding API找經緯度
  301. # def get_coordinate(addr):
  302. # url = 'https://maps.googleapis.com/maps/api/geocode/json'
  303. # params = {'sensor': 'false', 'address': addr, 'key': 'AIzaSyDKVm-6LBJqxrDJLEzJujGjZLVTfK0RiAE'}
  304. # r = requests.get(url, params=params)
  305. # results = r.json()['results']
  306. # location = results[0]['geometry']['location']
  307. # lat, lng = location['lat'], location['lng']
  308. # return lat, lng
  309. #爬蟲查找地址經緯度函數
  310. # def get_coordinate(addr):
  311. # options = webdriver.ChromeOptions()
  312. # options.add_argument("headless")
  313. # browser = webdriver.Chrome(executable_path='chromedriver', options=options)
  314. # browser.get("https://www.map.com.tw/")
  315. # search = browser.find_element_by_id("searchWord")
  316. # search.clear()
  317. # search.send_keys(addr)
  318. # browser.find_element_by_xpath("/html/body/form/div[10]/div[2]/img[2]").click()
  319. # time.sleep(2)
  320. # iframe = browser.find_elements_by_tag_name("iframe")[1]
  321. # browser.switch_to.frame(iframe)
  322. # coor_btn = browser.find_element_by_xpath("/html/body/form/div[4]/table/tbody/tr[3]/td/table/tbody/tr/td[2]")
  323. # coor_btn.click()
  324. # coor = browser.find_element_by_xpath("/html/body/form/div[5]/table/tbody/tr[2]/td")
  325. # coor = coor.text.strip().split(" ")
  326. # lat = coor[-1].split(":")[-1]
  327. # lng = coor[0].split(":")[-1]
  328. # browser.quit()
  329. # return lat, lng
  330. # 創建農場圖片資料夾,檔名為用戶名
  331. if not os.path.exists(app.config['UPLOAD_FOLDER'] + '//' + session['uname']):
  332. os.mkdir(app.config['UPLOAD_FOLDER'] + '//' + session['uname'])
  333. location = request.form['location']
  334. file = request.files['filename']
  335. farm_info = FarmInfo()
  336. if file and allowed_file(file.filename):
  337. # 避免檔名為類似 /../../../ filename的Directory traversal attack 發生
  338. filename = secure_filename(file.filename)
  339. path = os.path.join(app.config['UPLOAD_FOLDER'], session['uname'], filename)
  340. if '\\' in path:
  341. path = path.replace('\\','/')
  342. #這個儲存的格式/或\對f.save來說不會報錯
  343. file.save(path)
  344. farm_info.path = path
  345. if not location:
  346. pass
  347. else:
  348. farm_info.location = location
  349. lat, lng = get_coordinate(location)
  350. farm_info.loc_lat = lat
  351. farm_info.loc_lng = lng
  352. farm_info.user_id = session['id']
  353. current_time = dt.now()
  354. farm_info.datetime = current_time
  355. db.session.add(farm_info)
  356. D = request.form.to_dict()
  357. for module in D:
  358. if module != 'location':
  359. module_sn_num = ModuleSerialNumber()
  360. module_sn_num.module_name = module
  361. module_sn_num.sn_number = D[module]
  362. module_sn_num.user_id = session['id']
  363. module_sn_num.datetime = current_time
  364. db.session.add(module_sn_num)
  365. db.session.commit()
  366. return redirect('/register_number2')
  367. #登錄序號頁面2的訪問路徑
  368. @main.route('/register_number2', methods=['POST', 'GET'])
  369. def register_number2_views():
  370. username = session['uname']
  371. farm_info = FarmInfo.query.filter_by(user_id=session['id']).first()
  372. purchase_info = PurchaseInfo.query.filter_by(user_id=session['id']).first()
  373. monitor_num = purchase_info.monitor_num
  374. if request.method == 'GET':
  375. path = farm_info.path
  376. if path == '0':
  377. path = False
  378. lat = farm_info.loc_lat
  379. lng = farm_info.loc_lng
  380. if lat== '0' or lng == '0':
  381. lat = False
  382. lng = False
  383. return render_template('register_number2.html', params=locals())
  384. else:
  385. current_time = dt.now()
  386. for i in range(1, monitor_num + 1):
  387. node = NodePosition()
  388. node.node_name = "Nr." + str(i)
  389. if i < 10:
  390. node.pos_lat = request.form['lat0' + str(i)]
  391. node.pos_lng = request.form['lng0' + str(i)]
  392. else:
  393. node.pos_lat = request.form['lat' + str(i)]
  394. node.pos_lng = request.form['lng' + str(i)]
  395. node.user_id = session['id']
  396. node.datetime = current_time
  397. db.session.add(node)
  398. files = request.files.getlist('filename')
  399. num = 1
  400. current_time = dt.now()
  401. for file in files:
  402. if file and allowed_file(file.filename):
  403. # 避免檔名為類似 /../../../ filename的Directory traversal attack 發生
  404. filename = secure_filename(file.filename)
  405. path = os.path.join(app.config['UPLOAD_FOLDER'], session['uname'], filename)
  406. file.save(path)
  407. node_img = NodeImage()
  408. node_img.path = path
  409. node_img.node_name = 'Nr.' + str(num)
  410. node_img.user_id = session['id']
  411. node_img.datetime = current_time
  412. db.session.add(node_img)
  413. num += 1
  414. db.session.commit()
  415. return redirect('/schedule')
  416. #排程設定的訪問路徑
  417. @main.route('/schedule', methods=['POST', 'GET'])
  418. def schedule_views():
  419. username = session['uname']
  420. if request.method == 'GET':
  421. return render_template('schedule.html', params=locals())
  422. else:
  423. pass
  424. #用戶農場的訪問路徑
  425. @main.route('/map', methods=['POST', 'GET'])
  426. def map_views():
  427. username = session['uname']
  428. farm_info = FarmInfo.query.filter_by(user_id=session['id']).first()
  429. purchase_info = PurchaseInfo.query.filter_by(user_id=session['id']).first()
  430. monitor_num = purchase_info.monitor_num
  431. nodes = NodePosition.query.filter_by(user_id=session['id']).all()
  432. if request.method == 'GET':
  433. path = farm_info.path
  434. if path == '0':
  435. path = False
  436. lat = farm_info.loc_lat
  437. lng = farm_info.loc_lng
  438. return render_template('map.html', params=locals())
  439. else:
  440. pass
  441. # 退出的訪問路徑
  442. @main.route('/logout')
  443. def logout_views():
  444. if 'id' in session and 'uname' in session:
  445. del session['id']
  446. del session['uname']
  447. del session['status']
  448. return redirect('/')