123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517 |
- # 主業務邏輯中的視圖和路由的定義
- import os
- import datetime
- from flask import render_template, request, session, Response, url_for
- # 導入藍圖程序,用於構建路由
- from werkzeug.utils import redirect, secure_filename
- from . import main
- from manage import mqtt
- # 導入db,用於操作數據庫
- from manage import db, app
- # 導入實體類,用於操作數據庫
- from ..models import *
- import json
- from datetime import datetime as dt
- from sqlalchemy import text
- import socket
- import pickle
- import cv2
- import numpy as np
- import math
- import threading
- import time
- from flask_mqtt import Mqtt
- import requests
- import re
- import copy
- from selenium import webdriver
- from selenium.webdriver.support.ui import Select
- from bs4 import BeautifulSoup
- from time import sleep as sl
- from app import ALLOWED_EXTENSIONS
- import geocoder
- # 主頁的訪問路徑
- @main.route('/')
- def main_index():
- # 獲取登入信息
- if 'id' in session and 'uname' in session and 'status' in session:
- username = session['uname']
- if session['status'] == 1:
- return redirect('/purchase')
- elif session['status'] == 2:
- return redirect('/register_number')
- else:
- return render_template('index.html')
- # 登入頁面的訪問路徑
- @main.route('/login', methods=['GET', 'POST'])
- def login_views():
- if request.method == 'GET':
- if 'id' in session and 'uname' in session and 'status' in session:
- return redirect('/')
- else:
- return render_template('sign_in.html')
- else:
- # 接收前端傳過來的資料
- username = request.form['username']
- password = request.form['password']
- # 使用接收的用戶和密碼到資料庫中查詢
- user = User.query.filter_by(username=username, password=password).first()
- # 如果用戶存在,將信息保存置session並重定向回首頁,否則回登入頁
- if user:
- resp = redirect('/')
- # 判斷是否有記住密碼
- if 'rem' in request.form:
- sn = str(user.sn)
- max_age = 60 * 60 * 24 * 365
- resp.set_cookie("username", username, max_age=max_age)
- resp.set_cookie("sn", sn, max_age=max_age)
- session['uname'] = user.username
- session['id'] = user.sn
- session['status'] = user.status
- return resp
- else:
- errMsg = "Wrong login or password"
- return render_template('sign_in.html', errMsg=errMsg)
- # 註冊頁面的訪問路徑
- @main.route('/register', methods=['POST', "GET"])
- def register_views():
- if request.method == 'GET':
- return render_template('registration.html')
- else:
- # 獲取文本框的值並賦值給user實體對象
- user = User()
- user.firstname = request.form['firstname']
- user.lastname = request.form['lastname']
- user.mail = request.form['email']
- user.phone = request.form['phone']
- user.username = request.form['username']
- user.password = request.form['password']
- user.status = 1
- user.isActive = True
- # 將數據保存進資料庫 - 註冊
- db.session.add(user)
- # 手動提交,目的是為了獲取提交後的user的id
- db.session.commit()
- # 當user成功插入進資料庫之後,程序會自動將所有信息取出來在賦值給user
- # 完成登入的操作
- user = User.query.filter_by(username=user.username).first()
- session['id'] = user.sn
- session['uname'] = user.username
- session['status'] = user.status
- return redirect('/purchase')
- #登入重設密碼的頁面
- @main.route('/reset_password', methods=['POST', 'GET'])
- def reset_password_views():
- if request.method == 'GET':
- if 'mail' in session:
- del session['mail']
- return render_template('reset_pwd1.html')
- else:
- #如果有id在session裡,代表從reset_pwd2過來的
- if "mail" in session:
- new_pwd = request.form['new_pwd']
- confirm_pwd = request.form['confirm_pwd']
- #判斷密碼是否一致
- if new_pwd == confirm_pwd:
- mail = session['mail']
- user = User.query.filter_by(mail=mail).first()
- user.password = new_pwd
- db.session.add(user)
- del session['mail']
- #修改完後回登入頁
- return redirect('/login')
- else:
- errMsg = "Passwords does not match"
- return render_template('reset_pwd2.html', errMsg=errMsg)
- email = request.form['email']
- user = User.query.filter_by(mail=email).first()
- if user:
- session['mail'] = user.mail
- return render_template('reset_pwd2.html')
- else:
- errMsg = "Wrong email.Please try again"
- return render_template('reset_pwd1.html', errMsg=errMsg)
- #驗證email訪問路徑
- @main.route('/check_email')
- def check_email_views():
- email = request.args['email']
- user = User.query.filter_by(mail=email).first()
- if user:
- result = {"errMsg":" "}
- else:
- result = {"pass":" "}
- return json.dumps(result)
- #驗證username訪問路徑
- @main.route('/check_username')
- def check_username_views():
- username = request.args['username']
- user = User.query.filter_by(username=username).first()
- if user:
- result = {"errMsg":" "}
- else:
- result = {"pass":" "}
- return json.dumps(result)
- #購買頁面的訪問路徑
- @main.route('/purchase', methods=['POST', 'GET'])
- def purchase_views():
- username = session['uname']
- if request.method == 'GET':
- return render_template('purchase.html', params=locals())
- else:
- print(request.form)
- purchase_info = PurchaseInfo()
- purchase_info.loc_length = request.form['length']
- purchase_info.loc_width = request.form['width']
- purchase_info.location = request.form['location']
- purchase_info.monitor_num = request.form['monitor_num']
- purchase_info.connect = request.form['connection']
- purchase_info.user_id = session['id']
- purchase_info.datetime = dt.now()
- db.session.add(purchase_info)
- db.session.commit()
- return redirect('/monitor')
- #監控功能頁面的訪問路徑
- @main.route('/monitor', methods=['POST', 'GET'])
- def monitor_views():
- username = session['uname']
- purchase_info = PurchaseInfo.query.filter_by(user_id=session['id']).first()
- monitor_num = purchase_info.monitor_num
- if request.method == 'GET':
- return render_template('monitor.html', params=locals())
- else:
- print(request.form)
- D = {}
- for i in range(1, monitor_num + 1):
- d = {}
- for monitor in request.form.getlist('features' + str(i)):
- d[monitor] = []
- D['node' + str(i)] = d
- session['node_info1'] = D
- # node_info = NodeInfo()
- # node_info.node_info = str(D)
- # node_info.purchase_id = purchase_info.sn
- # db.session.add(node_info)
- # db.session.commit()
- return redirect('/module')
- #模組頁面的訪問路徑
- @main.route('/module', methods=['POST', 'GET'])
- def module_views():
- username = session['uname']
- user = User.query.filter_by(username=username).first()
- purchase_id = user.purchase_info.sn
- # node_info = NodeInfo.query.filter_by(purchase_id=purchase_id).first()
- # node_info = node_info.node_info
- if request.method == 'GET':
- #將字串變成字典(eval函數:用来执行一个字符串表达式,并返回表达式的值)
- # node_info = eval(node_info)
- node_info = session['node_info1']
- print(node_info)
- D = {}
- for node in node_info:
- l = []
- for monitor in node_info[node]:
- l.append(monitor)
- D[node] = l
- sort_L = []
- #從node1開始往後按順序排
- for i in range(1, len(D) + 1):
- sort_L.append(D['node' + str(i)])
- sensors = SensorList.query.all()
- sensor_list = []
- for sensor in sensors:
- sensor_list.append(sensor.toDict())
- return render_template('module.html', params=locals())
- else:
- monitor_num = user.purchase_info.monitor_num
- D = session['node_info1']
- #深拷貝區分session['node_info1']與session['node_info2']
- A = copy.deepcopy(D)
- for i in range(1, monitor_num + 1):
- try:
- for module in request.form.getlist('weather_module' + str(i)):
- A['node' + str(i)]['weather'].append(module)
- except Exception as e:
- pass
- try:
- for module in request.form.getlist('irrigation_module' + str(i)):
- A['node' + str(i)]['irrigation'].append(module)
- except Exception as e:
- pass
- try:
- for module in request.form.getlist('water_module' + str(i)):
- A['node' + str(i)]['water'].append(module)
- except Exception as e:
- pass
- session['node_info2'] = A
- return redirect('/list')
- #清單頁面的訪問路徑
- @main.route('/list', methods=['POST', 'GET'])
- def list_views():
- username = session['uname']
- purchase_info = PurchaseInfo.query.filter_by(user_id=session['id']).first()
- D = session['node_info2']
- if request.method == 'GET':
- sort_L = []
- for i in range(1, len(D) + 1):
- sort_L.append(json.dumps(D['node' + str(i)]))
- sensors = SensorList.query.all()
- sensor_list = []
- for sensor in sensors:
- sensor_list.append(sensor.toDict())
- return render_template('list.html', params=locals())
- else:
- user = User.query.filter_by(username=username).first()
- user.status = 2
- session['status'] = user.status
- print(session['node_info2'])
- node_info = NodeInfo()
- node_info.node_info = str(session['node_info2'])
- node_info.user_id = session['id']
- db.session.add(node_info)
- db.session.add(user)
- db.session.commit()
- return redirect('/register_number')
- #過濾前端傳過來文件副檔名函數
- def allowed_file(filename):
- return '.' in filename and \
- filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
- #登錄序號頁面1的訪問路徑
- @main.route('/register_number', methods=['POST', 'GET'])
- def register_number_views():
- username = session['uname']
- purchase_info = PurchaseInfo.query.filter_by(user_id=session['id']).first()
- node_info = NodeInfo.query.filter_by(user_id=session['id']).first()
- D = eval(node_info.node_info)
- if request.method == 'GET':
- sort_L = []
- for i in range(1, len(D) + 1):
- sort_L.append(json.dumps(D['node' + str(i)]))
- sensors = SensorList.query.all()
- sensor_list = []
- for sensor in sensors:
- sensor_list.append(sensor.toDict())
- return render_template('register_number.html', params=locals())
- else:
- #使用geocoder庫找經緯度
- def get_coordinate(addr):
- g = geocoder.arcgis(u"" + addr)
- lat, lng = g.latlng
- return lat, lng
- #使用Geocoding API找經緯度
- # def get_coordinate(addr):
- # url = 'https://maps.googleapis.com/maps/api/geocode/json'
- # params = {'sensor': 'false', 'address': addr, 'key': 'AIzaSyDKVm-6LBJqxrDJLEzJujGjZLVTfK0RiAE'}
- # r = requests.get(url, params=params)
- # results = r.json()['results']
- # location = results[0]['geometry']['location']
- # lat, lng = location['lat'], location['lng']
- # return lat, lng
- #爬蟲查找地址經緯度函數
- # def get_coordinate(addr):
- # options = webdriver.ChromeOptions()
- # options.add_argument("headless")
- # browser = webdriver.Chrome(executable_path='chromedriver', options=options)
- # browser.get("https://www.map.com.tw/")
- # search = browser.find_element_by_id("searchWord")
- # search.clear()
- # search.send_keys(addr)
- # browser.find_element_by_xpath("/html/body/form/div[10]/div[2]/img[2]").click()
- # time.sleep(2)
- # iframe = browser.find_elements_by_tag_name("iframe")[1]
- # browser.switch_to.frame(iframe)
- # coor_btn = browser.find_element_by_xpath("/html/body/form/div[4]/table/tbody/tr[3]/td/table/tbody/tr/td[2]")
- # coor_btn.click()
- # coor = browser.find_element_by_xpath("/html/body/form/div[5]/table/tbody/tr[2]/td")
- # coor = coor.text.strip().split(" ")
- # lat = coor[-1].split(":")[-1]
- # lng = coor[0].split(":")[-1]
- # browser.quit()
- # return lat, lng
- # 創建農場圖片資料夾,檔名為用戶名
- if not os.path.exists(app.config['UPLOAD_FOLDER'] + '//' + session['uname']):
- os.mkdir(app.config['UPLOAD_FOLDER'] + '//' + session['uname'])
- location = request.form['location']
- file = request.files['filename']
- farm_info = FarmInfo()
- if file and allowed_file(file.filename):
- # 避免檔名為類似 /../../../ filename的Directory traversal attack 發生
- filename = secure_filename(file.filename)
- path = os.path.join(app.config['UPLOAD_FOLDER'], session['uname'], filename)
- if '\\' in path:
- path = path.replace('\\','/')
- #這個儲存的格式/或\對f.save來說不會報錯
- file.save(path)
- farm_info.path = path
- if not location:
- pass
- else:
- farm_info.location = location
- lat, lng = get_coordinate(location)
- farm_info.loc_lat = lat
- farm_info.loc_lng = lng
- farm_info.user_id = session['id']
- current_time = dt.now()
- farm_info.datetime = current_time
- db.session.add(farm_info)
- D = request.form.to_dict()
- for module in D:
- if module != 'location':
- module_sn_num = ModuleSerialNumber()
- module_sn_num.module_name = module
- module_sn_num.sn_number = D[module]
- module_sn_num.user_id = session['id']
- module_sn_num.datetime = current_time
- db.session.add(module_sn_num)
- db.session.commit()
- return redirect('/register_number2')
- #登錄序號頁面2的訪問路徑
- @main.route('/register_number2', methods=['POST', 'GET'])
- def register_number2_views():
- username = session['uname']
- farm_info = FarmInfo.query.filter_by(user_id=session['id']).first()
- purchase_info = PurchaseInfo.query.filter_by(user_id=session['id']).first()
- monitor_num = purchase_info.monitor_num
- if request.method == 'GET':
- path = farm_info.path
- if path == '0':
- path = False
- lat = farm_info.loc_lat
- lng = farm_info.loc_lng
- if lat== '0' or lng == '0':
- lat = False
- lng = False
- return render_template('register_number2.html', params=locals())
- else:
- current_time = dt.now()
- for i in range(1, monitor_num + 1):
- node = NodePosition()
- node.node_name = "Nr." + str(i)
- if i < 10:
- node.pos_lat = request.form['lat0' + str(i)]
- node.pos_lng = request.form['lng0' + str(i)]
- else:
- node.pos_lat = request.form['lat' + str(i)]
- node.pos_lng = request.form['lng' + str(i)]
- node.user_id = session['id']
- node.datetime = current_time
- db.session.add(node)
- files = request.files.getlist('filename')
- num = 1
- current_time = dt.now()
- for file in files:
- if file and allowed_file(file.filename):
- # 避免檔名為類似 /../../../ filename的Directory traversal attack 發生
- filename = secure_filename(file.filename)
- path = os.path.join(app.config['UPLOAD_FOLDER'], session['uname'], filename)
- file.save(path)
- node_img = NodeImage()
- node_img.path = path
- node_img.node_name = 'Nr.' + str(num)
- node_img.user_id = session['id']
- node_img.datetime = current_time
- db.session.add(node_img)
- num += 1
- db.session.commit()
- return redirect('/schedule')
- #排程設定的訪問路徑
- @main.route('/schedule', methods=['POST', 'GET'])
- def schedule_views():
- username = session['uname']
- if request.method == 'GET':
- return render_template('schedule.html', params=locals())
- else:
- pass
- #用戶農場的訪問路徑
- @main.route('/map', methods=['POST', 'GET'])
- def map_views():
- username = session['uname']
- farm_info = FarmInfo.query.filter_by(user_id=session['id']).first()
- purchase_info = PurchaseInfo.query.filter_by(user_id=session['id']).first()
- monitor_num = purchase_info.monitor_num
- nodes = NodePosition.query.filter_by(user_id=session['id']).all()
- if request.method == 'GET':
- path = farm_info.path
- if path == '0':
- path = False
- lat = farm_info.loc_lat
- lng = farm_info.loc_lng
- return render_template('map.html', params=locals())
- else:
- pass
- # 退出的訪問路徑
- @main.route('/logout')
- def logout_views():
- if 'id' in session and 'uname' in session:
- del session['id']
- del session['uname']
- del session['status']
- return redirect('/')
|