Jelajahi Sumber

second commit

Benson 3 tahun lalu
induk
melakukan
c1b3a967eb
100 mengubah file dengan 5335 tambahan dan 0 penghapusan
  1. TEMPAT SAMPAH
      BBend-Test-JWT.zip
  2. 8 0
      BBend-Test-JWT/.idea/.gitignore
  3. 21 0
      BBend-Test-JWT/.idea/Sixth-BBend.iml
  4. 4 0
      BBend-Test-JWT/.idea/encodings.xml
  5. 6 0
      BBend-Test-JWT/.idea/inspectionProfiles/profiles_settings.xml
  6. 10 0
      BBend-Test-JWT/.idea/misc.xml
  7. 8 0
      BBend-Test-JWT/.idea/modules.xml
  8. 6 0
      BBend-Test-JWT/.idea/vcs.xml
  9. 1 0
      BBend-Test-JWT/.~lock.ItemFile.csv#
  10. TEMPAT SAMPAH
      BBend-Test-JWT/__pycache__/manage.cpython-35.pyc
  11. TEMPAT SAMPAH
      BBend-Test-JWT/__pycache__/manage.cpython-36.pyc
  12. 92 0
      BBend-Test-JWT/app/__init__.py
  13. TEMPAT SAMPAH
      BBend-Test-JWT/app/__pycache__/__init__.cpython-35.pyc
  14. TEMPAT SAMPAH
      BBend-Test-JWT/app/__pycache__/__init__.cpython-36.pyc
  15. TEMPAT SAMPAH
      BBend-Test-JWT/app/__pycache__/models.cpython-35.pyc
  16. TEMPAT SAMPAH
      BBend-Test-JWT/app/__pycache__/models.cpython-36.pyc
  17. 5 0
      BBend-Test-JWT/app/main/__init__.py
  18. TEMPAT SAMPAH
      BBend-Test-JWT/app/main/__pycache__/__init__.cpython-35.pyc
  19. TEMPAT SAMPAH
      BBend-Test-JWT/app/main/__pycache__/__init__.cpython-36.pyc
  20. TEMPAT SAMPAH
      BBend-Test-JWT/app/main/__pycache__/views.cpython-35.pyc
  21. TEMPAT SAMPAH
      BBend-Test-JWT/app/main/__pycache__/views.cpython-36.pyc
  22. 436 0
      BBend-Test-JWT/app/main/views.py
  23. 187 0
      BBend-Test-JWT/app/models.py
  24. 112 0
      BBend-Test-JWT/app/static/css/registration.css
  25. 103 0
      BBend-Test-JWT/app/static/css/reset_pwd1.css
  26. 106 0
      BBend-Test-JWT/app/static/css/reset_pwd2.css
  27. 116 0
      BBend-Test-JWT/app/static/css/sign_in.css
  28. TEMPAT SAMPAH
      BBend-Test-JWT/app/static/farm_img/benson/2020731_200803.jpg
  29. TEMPAT SAMPAH
      BBend-Test-JWT/app/static/farm_img/benson/274205.jpg
  30. TEMPAT SAMPAH
      BBend-Test-JWT/app/static/farm_img/benson/Pasted_Image_2020-11-26_09-58-20.png
  31. TEMPAT SAMPAH
      BBend-Test-JWT/app/static/farm_img/benson/material-design-color-chart.png
  32. TEMPAT SAMPAH
      BBend-Test-JWT/app/static/farm_img/benson/psfi.jpg
  33. TEMPAT SAMPAH
      BBend-Test-JWT/app/static/farm_img/benson/rosgraph.png
  34. TEMPAT SAMPAH
      BBend-Test-JWT/app/static/farm_img/benson/screenshot.png
  35. TEMPAT SAMPAH
      BBend-Test-JWT/app/static/img/battery.png
  36. TEMPAT SAMPAH
      BBend-Test-JWT/app/static/img/logo_new.png
  37. TEMPAT SAMPAH
      BBend-Test-JWT/app/static/img/psfi.jpg
  38. 100 0
      BBend-Test-JWT/app/static/js/registration.js
  39. 3 0
      BBend-Test-JWT/app/static/js/reset_pwd1.js
  40. 3 0
      BBend-Test-JWT/app/static/js/reset_pwd2.js
  41. 3 0
      BBend-Test-JWT/app/static/js/sign_in.js
  42. 331 0
      BBend-Test-JWT/app/templates/add_sensor.html
  43. 708 0
      BBend-Test-JWT/app/templates/add_server.html
  44. 336 0
      BBend-Test-JWT/app/templates/burn_program.html
  45. 247 0
      BBend-Test-JWT/app/templates/incoming_check.html
  46. 274 0
      BBend-Test-JWT/app/templates/index.html
  47. 246 0
      BBend-Test-JWT/app/templates/modify_permissions.html
  48. 108 0
      BBend-Test-JWT/app/templates/registration.html
  49. 60 0
      BBend-Test-JWT/app/templates/reset_pwd1.html
  50. 66 0
      BBend-Test-JWT/app/templates/reset_pwd2.html
  51. 92 0
      BBend-Test-JWT/app/templates/sign_in.html
  52. 38 0
      BBend-Test-JWT/app/templates/test.html
  53. 6 0
      BBend-Test-JWT/app/user/__init__.py
  54. TEMPAT SAMPAH
      BBend-Test-JWT/app/user/__pycache__/__init__.cpython-35.pyc
  55. TEMPAT SAMPAH
      BBend-Test-JWT/app/user/__pycache__/__init__.cpython-36.pyc
  56. TEMPAT SAMPAH
      BBend-Test-JWT/app/user/__pycache__/views.cpython-35.pyc
  57. TEMPAT SAMPAH
      BBend-Test-JWT/app/user/__pycache__/views.cpython-36.pyc
  58. 6 0
      BBend-Test-JWT/app/user/views.py
  59. 272 0
      BBend-Test-JWT/manage.py
  60. 1 0
      BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/INSTALLER
  61. 28 0
      BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/LICENSE.rst
  62. 137 0
      BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/METADATA
  63. 49 0
      BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/RECORD
  64. 0 0
      BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/REQUESTED
  65. 6 0
      BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/WHEEL
  66. 3 0
      BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/entry_points.txt
  67. 1 0
      BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/top_level.txt
  68. 1 0
      BBend-Test-JWT/venv/Lib/site-packages/Jinja2-2.11.2.dist-info/INSTALLER
  69. 28 0
      BBend-Test-JWT/venv/Lib/site-packages/Jinja2-2.11.2.dist-info/LICENSE.rst
  70. 106 0
      BBend-Test-JWT/venv/Lib/site-packages/Jinja2-2.11.2.dist-info/METADATA
  71. 59 0
      BBend-Test-JWT/venv/Lib/site-packages/Jinja2-2.11.2.dist-info/RECORD
  72. 6 0
      BBend-Test-JWT/venv/Lib/site-packages/Jinja2-2.11.2.dist-info/WHEEL
  73. 3 0
      BBend-Test-JWT/venv/Lib/site-packages/Jinja2-2.11.2.dist-info/entry_points.txt
  74. 1 0
      BBend-Test-JWT/venv/Lib/site-packages/Jinja2-2.11.2.dist-info/top_level.txt
  75. 1 0
      BBend-Test-JWT/venv/Lib/site-packages/MarkupSafe-1.1.1.dist-info/INSTALLER
  76. 28 0
      BBend-Test-JWT/venv/Lib/site-packages/MarkupSafe-1.1.1.dist-info/LICENSE.rst
  77. 103 0
      BBend-Test-JWT/venv/Lib/site-packages/MarkupSafe-1.1.1.dist-info/METADATA
  78. 15 0
      BBend-Test-JWT/venv/Lib/site-packages/MarkupSafe-1.1.1.dist-info/RECORD
  79. 5 0
      BBend-Test-JWT/venv/Lib/site-packages/MarkupSafe-1.1.1.dist-info/WHEEL
  80. 1 0
      BBend-Test-JWT/venv/Lib/site-packages/MarkupSafe-1.1.1.dist-info/top_level.txt
  81. 1 0
      BBend-Test-JWT/venv/Lib/site-packages/Werkzeug-1.0.1.dist-info/INSTALLER
  82. 28 0
      BBend-Test-JWT/venv/Lib/site-packages/Werkzeug-1.0.1.dist-info/LICENSE.rst
  83. 128 0
      BBend-Test-JWT/venv/Lib/site-packages/Werkzeug-1.0.1.dist-info/METADATA
  84. 101 0
      BBend-Test-JWT/venv/Lib/site-packages/Werkzeug-1.0.1.dist-info/RECORD
  85. 6 0
      BBend-Test-JWT/venv/Lib/site-packages/Werkzeug-1.0.1.dist-info/WHEEL
  86. 1 0
      BBend-Test-JWT/venv/Lib/site-packages/Werkzeug-1.0.1.dist-info/top_level.txt
  87. TEMPAT SAMPAH
      BBend-Test-JWT/venv/Lib/site-packages/__pycache__/easy_install.cpython-35.pyc
  88. 110 0
      BBend-Test-JWT/venv/Lib/site-packages/_distutils_hack/__init__.py
  89. TEMPAT SAMPAH
      BBend-Test-JWT/venv/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-35.pyc
  90. TEMPAT SAMPAH
      BBend-Test-JWT/venv/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-35.pyc
  91. 1 0
      BBend-Test-JWT/venv/Lib/site-packages/_distutils_hack/override.py
  92. 1 0
      BBend-Test-JWT/venv/Lib/site-packages/click-7.1.2.dist-info/INSTALLER
  93. 28 0
      BBend-Test-JWT/venv/Lib/site-packages/click-7.1.2.dist-info/LICENSE.rst
  94. 102 0
      BBend-Test-JWT/venv/Lib/site-packages/click-7.1.2.dist-info/METADATA
  95. 40 0
      BBend-Test-JWT/venv/Lib/site-packages/click-7.1.2.dist-info/RECORD
  96. 6 0
      BBend-Test-JWT/venv/Lib/site-packages/click-7.1.2.dist-info/WHEEL
  97. 1 0
      BBend-Test-JWT/venv/Lib/site-packages/click-7.1.2.dist-info/top_level.txt
  98. 79 0
      BBend-Test-JWT/venv/Lib/site-packages/click/__init__.py
  99. TEMPAT SAMPAH
      BBend-Test-JWT/venv/Lib/site-packages/click/__pycache__/__init__.cpython-35.pyc
  100. 0 0
      BBend-Test-JWT/venv/Lib/site-packages/click/__pycache__/_bashcomplete.cpython-35.pyc

TEMPAT SAMPAH
BBend-Test-JWT.zip


+ 8 - 0
BBend-Test-JWT/.idea/.gitignore

@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/

+ 21 - 0
BBend-Test-JWT/.idea/Sixth-BBend.iml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="PYTHON_MODULE" version="4">
+  <component name="Flask">
+    <option name="enabled" value="true" />
+  </component>
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/venv" />
+    </content>
+    <orderEntry type="jdk" jdkName="Python 3.6" jdkType="Python SDK" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+  <component name="TemplatesService">
+    <option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
+    <option name="TEMPLATE_FOLDERS">
+      <list>
+        <option value="$MODULE_DIR$/../Sixth\templates" />
+      </list>
+    </option>
+  </component>
+</module>

+ 4 - 0
BBend-Test-JWT/.idea/encodings.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding" addBOMForNewFiles="with NO BOM" />
+</project>

+ 6 - 0
BBend-Test-JWT/.idea/inspectionProfiles/profiles_settings.xml

@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <settings>
+    <option name="USE_PROJECT_PROFILE" value="false" />
+    <version value="1.0" />
+  </settings>
+</component>

+ 10 - 0
BBend-Test-JWT/.idea/misc.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="JavaScriptSettings">
+    <option name="languageLevel" value="ES6" />
+  </component>
+  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6" project-jdk-type="Python SDK" />
+  <component name="PyCharmProfessionalAdvertiser">
+    <option name="shown" value="true" />
+  </component>
+</project>

+ 8 - 0
BBend-Test-JWT/.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/Sixth-BBend.iml" filepath="$PROJECT_DIR$/.idea/Sixth-BBend.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
BBend-Test-JWT/.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 1 - 0
BBend-Test-JWT/.~lock.ItemFile.csv#

@@ -0,0 +1 @@
+,benson,ubuntu,29.04.2021 11:52,file:///home/benson/.config/libreoffice/4;

TEMPAT SAMPAH
BBend-Test-JWT/__pycache__/manage.cpython-35.pyc


TEMPAT SAMPAH
BBend-Test-JWT/__pycache__/manage.cpython-36.pyc


+ 92 - 0
BBend-Test-JWT/app/__init__.py

@@ -0,0 +1,92 @@
+#對整個應用做初始化操作
+#主要工作:
+# 1.構建Flask的應用以及各種配置
+#2.構建SQLAlchemy的應用
+
+from flask import Flask
+from flask_sqlalchemy import SQLAlchemy
+import pymysql
+import eventlet
+from flask_mqtt import Mqtt
+from datetime import timedelta
+from flask_jwt_extended import JWTManager
+from flask_socketio import SocketIO
+
+jwt = JWTManager()
+
+#綠化(綠色線程)所有系統模組,實現IO多路複用
+eventlet.monkey_patch()
+
+pymysql.install_as_MySQLdb()
+
+#設置上傳文件路徑
+UPLOAD_FOLDER = 'app/static/farm_img'
+#設置允許文件副檔名
+ALLOWED_EXTENSIONS = set(['pdf', 'png', 'jpg', 'jpeg', 'gif'])
+
+
+def create_app():
+    global UPLOAD_FOLDER
+    app = Flask(__name__)
+    #配置啟動模式為調適模式
+    # app.config['DEBUG'] = True
+    #配置數據庫的連接字符串
+    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://sixth:skyeye@52.69.200.169:3306/Sixth'
+    #配置數據庫內容再更新時自動提交
+    app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
+    #配置session所需要的秘鑰
+    app.config['SECRET_KEY'] = 'you guess'
+    # template 有修改後,會自動去更新
+    app.config['TEMPLATES_AUTO_RELOAD'] = True
+    # 如果设置成True(默认情况),Flask - SQLAlchemy将会追踪对象的修改并且发送信号。这需要额外的内存, 如果不必要的可以禁用它
+    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
+    #資料库连接池的大小。默认是数据库引擎的默认值 (通常是5)
+    app.config['SQLALCHEMY_POOL_SIZE'] = 100
+    #指定資料库连接池的超时时间。默认是 10
+    app.config['SQLALCHEMY_POOL_TIMEOUT'] = 60 * 60
+    #自动回收连接的秒数。这对 MySQL 是必须的,默认 情况下 MySQL 会自动移除闲置 8 小时或者以上的连接。 需要注意地是如果使用 MySQL 的话, Flask-SQLAlchemy 会自动地设置这个值为 2 小时
+    app.config['SQLALCHEMY_MAX_OVERFLOW'] = 15
+    #設置session有效期為31天
+    # app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=31)
+
+    #設置上傳文件的路徑
+    app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
+    # 如果超過檔案大小限制,Flask將會拋出RequestEntityTooLarge的例外錯誤。
+    app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16MB
+
+    # 設定 JWT 密鑰
+    app.config['JWT_SECRET_KEY'] = 'this-should-be-change'
+    jwt.init_app(app)
+
+    # app.config['JWT_TOKEN_LOCATION'] = ['headers', 'query_string']
+    # app.config['JWT_TOKEN_LOCATION'] = ['query_string']
+    # app.config['JWT_QUERY_STRING_NAME'] = 'jwt'
+
+    app.config['PROPAGATE_EXCEPTIONS'] = True
+
+    app.config['SECRET'] = 'my secret key'
+    #MQTT相關設置
+    app.config['MQTT_BROKER_URL'] = '60.250.156.234'
+    app.config['MQTT_BROKER_PORT'] = 1883
+    app.config['MQTT_USERNAME'] = 'aisky-client'
+    app.config['MQTT_PASSWORD'] = 'aiskyc'
+    #將發送ping到代理的時間間隔設置60秒
+    app.config['MQTT_KEEPALIVE'] = 60
+    #出於測試目的將TLS設置為禁用
+    app.config['MQTT_TLS_ENABLED'] = False
+
+    #數據庫的初始化
+    db = SQLAlchemy(app)
+    db.init_app(app)
+    mqtt = Mqtt(app)
+    socketio = SocketIO(app, cors_allowed_origins='*')
+
+
+    #將main藍圖程序與app關聯到一起
+    from .main import main as main_blueprint
+    app.register_blueprint(main_blueprint)
+    #將user藍圖程序與app關聯到一起
+    from .user import user as user_blueprint
+    app.register_blueprint(user_blueprint)
+
+    return app, db, mqtt, socketio

TEMPAT SAMPAH
BBend-Test-JWT/app/__pycache__/__init__.cpython-35.pyc


TEMPAT SAMPAH
BBend-Test-JWT/app/__pycache__/__init__.cpython-36.pyc


TEMPAT SAMPAH
BBend-Test-JWT/app/__pycache__/models.cpython-35.pyc


TEMPAT SAMPAH
BBend-Test-JWT/app/__pycache__/models.cpython-36.pyc


+ 5 - 0
BBend-Test-JWT/app/main/__init__.py

@@ -0,0 +1,5 @@
+#main 目錄: 包含主要的業務邏輯的路由和視圖
+# __init__.py : 對主業務邏輯程序的初始化操作
+from flask import Blueprint
+main = Blueprint('main',__name__)
+from . import views

TEMPAT SAMPAH
BBend-Test-JWT/app/main/__pycache__/__init__.cpython-35.pyc


TEMPAT SAMPAH
BBend-Test-JWT/app/main/__pycache__/__init__.cpython-36.pyc


TEMPAT SAMPAH
BBend-Test-JWT/app/main/__pycache__/views.cpython-35.pyc


TEMPAT SAMPAH
BBend-Test-JWT/app/main/__pycache__/views.cpython-36.pyc


+ 436 - 0
BBend-Test-JWT/app/main/views.py

@@ -0,0 +1,436 @@
+# 主業務邏輯中的視圖和路由的定義
+import os
+import datetime
+from flask import render_template, request, session, Response, url_for, make_response
+# 導入藍圖程序,用於構建路由
+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
+from flask import jsonify
+from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity
+import paramiko
+import git
+import shutil
+from manage import socketio
+
+
+# 主頁的訪問路徑
+@main.route('/')
+# @jwt_required
+def main_index():
+    # 獲取登入信息
+    if 'token' in session and 'uname' in session:
+        username = session['uname']
+        return redirect('/index')
+    else:
+        return render_template('sign_in.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()
+        #檢查原密碼與哈希過的密碼是否吻合
+        # if user and user.check_hash_password(password):
+        # 如果用戶存在,將信息保存置session並重定向回首頁,否則回登入頁
+        if user:
+            # resp = redirect('/')
+            # resp = make_response('')
+            # 判斷是否有記住密碼
+            if 'rem' in request.form:
+                # sn = str(user.sn)
+                # 如果設置了 session.permanent 為 True,那麽過期時間是31天
+                session.permanent = True
+                #設置cookie
+                # max_age = 60 * 60 * 24 * 365
+                # resp.set_cookie("username", username, max_age=max_age)
+                # resp.set_cookie("sn", sn, max_age=max_age)
+
+            #可設置tokens時效
+            expires = datetime.timedelta(minutes=30)
+            access_token = create_access_token(identity=user.username, expires_delta=expires)
+            # access_token = create_access_token(identity=user.username)
+            print(access_token)
+
+            session['token'] = access_token
+            session['uname'] = user.username
+            # session['id'] = user.sn
+            # session['status'] = user.status
+            return jsonify(access_token=access_token)
+        else:
+            errMsg = "Wrong login or password"
+            # return render_template('sign_in.html', errMsg=errMsg)
+            return jsonify(errMsg=errMsg)
+
+
+# 註冊頁面的訪問路徑
+@main.route('/register', methods=['POST', "GET"])
+def register_views():
+    if request.method == 'GET':
+        return render_template('registration.html')
+    else:
+        # 獲取文本框的值並賦值給user實體對象
+        #哈希加密版本
+        # username = request.form['username']
+        # password = request.form['password']
+        # user = User(username=username, password=password)
+        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()
+        # 可設置tokens時效
+        expires = datetime.timedelta(minutes=30)
+        access_token = create_access_token(identity=user.username, expires_delta=expires)
+        # access_token = create_access_token(identity=user.username)
+
+        session['token'] = access_token
+        # session['id'] = user.sn
+        session['uname'] = user.username
+        # session['status'] = user.status
+        return jsonify(access_token=access_token)
+        # return redirect('/')
+
+
+#登入重設密碼的頁面
+@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('/index', methods=['POST', 'GET'])
+def index_views():
+    token = session['token']
+    username = session['uname']
+    if request.method == 'GET':
+        return render_template('index.html', params=locals())
+    else:
+        pass
+
+#進貨檢測的訪問路徑
+@main.route('/incoming_check', methods=['POST', 'GET'])
+def incoming_check_views():
+    # print("test")
+    username = session['uname']
+    if request.method == 'GET':
+        # print("test2")
+        # return jsonify(status=200)
+        return render_template('incoming_check.html', params=locals())
+
+        # 方法內可透過get_jwt_identity之前放在token的identity內的內容:使用者名稱
+        # identity = get_jwt_identity()
+        # return jsonify(identity=identity)
+    else:
+        pass
+
+
+#感測器燒錄的訪問路徑
+@main.route('/burn_program', methods=['POST', 'GET'])
+def burn_program_views():
+    username = session['uname']
+    if request.method == 'GET':
+        sensors = SensorList.query.all()
+        sensor_list = []
+        for sensor in sensors:
+            sensor_list.append(sensor.toDict())
+
+
+        return render_template('burn_program.html', params=locals())
+    else:
+        import json
+        payload = {}
+        if request.form['airTem']:
+            payload = {"command":"system_update", "url":"http://60.250.156.230:3000/Benson/TestOTA.git"}
+
+        json = json.dumps(payload)
+        mqtt.publish(json)
+        res = {"status": 1}
+        return json.dumps(res)
+
+#修改權限的訪問路徑
+@main.route('/modify_permissions', methods=['POST', 'GET'])
+def modify_permissions_views():
+    username = session['uname']
+    if request.method == 'GET':
+        return render_template('modify_permissions.html', params=locals())
+    else:
+        pass
+
+#新增感測器的訪問路徑
+@main.route('/add_sensor', methods=['POST', 'GET'])
+def add_sensor_views():
+    username = session['uname']
+    if request.method == 'GET':
+        return render_template('add_sensor.html', params=locals())
+    else:
+        try:
+            ch_name = request.form['ch_name']
+            en_name = request.form['en_name']
+            version = request.form['version']
+
+            sensor = SensorList()
+            sensor.ch_name = ch_name
+            sensor.en_name = en_name
+            sensor.version = version
+            sensor.datetime = dt.now()
+            db.session.add(sensor)
+            db.session.commit()
+
+            return "新增成功!"
+        except Exception as e:
+            return 'ERROR:' + e
+
+# @socketio.on('connect_event')
+# def connected_msg(msg):
+#     print("connect success")
+#     print(msg)
+#     socketio.emit('stdout', 'success')
+#     print(socketio)
+#
+# D = {"ssh_content":0}
+#
+# #建置伺服器的訪問路徑
+# @main.route('/add_server', methods=['POST', 'GET'])
+# def add_server_views():
+#     username = session['uname']
+#     L = []
+#     if request.method == 'GET':
+#         repo = git.Repo.init(path='.')
+#         new_repo = git.Repo.clone_from(url='http://60.250.156.230:3000/benson/TestSSH.git', to_path='../new')
+#         with open('/home/benson/Project/new/All_installv3.2.sh') as f:
+#             D['ssh_content'] = f.read().split('\n')[0:-1]
+#             ssh_content = D['ssh_content']
+#             print(D['ssh_content'])
+#
+#             #刪除非空資料夾
+#             try:
+#                 shutil.rmtree('/home/benson/Project/new')
+#             except OSError as e:
+#                 print(f"Error:{e.strerror}")
+#
+#         for i in range(0, len(D['ssh_content'])):
+#             if "#" in D['ssh_content'][i] or D['ssh_content'][i] == '' or D['ssh_content'][i] == ' ':
+#                 continue
+#             if "sudo" in D['ssh_content'][i] or "echo" in D['ssh_content'][i]:
+#                 L.append(D['ssh_content'][i])
+#         return render_template('add_server.html', params=locals())
+#     else:
+#         print(D['ssh_content'])
+#         L = []
+#         d = request.form.to_dict()
+#         ip = d['ip']
+#         print(ip)
+#         try:
+#             # 建立一個sshclient物件
+#             ssh = paramiko.SSHClient()
+#             # 允許將信任的主機自動加入到host_allow 列表,此方法必須放在connect方法的前面
+#             ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+#             # 指定本地的RSA私鑰檔案,如果建立金鑰對時設定的有密碼,password為設定的密碼,如無不用指定password引數
+#             # pkey = paramiko.RSAKey.from_private_key_file('/home/super/.ssh/id_rsa', password='12345')
+#             # pkey = paramiko.RSAKey.from_private_key_file('/home/ptop/topicjie/scripts/keys/id_rsa')
+#             # 建立連線
+#             # ssh.connect(hostname=ip,
+#             #             port=22,
+#             #             username='gs1801',
+#             #             pkey=pkey)
+#             with open('/home/benson/test11.sh') as f:
+#                 content = f.read().split('\n')[0:-1]
+#             print(content)
+#             # L = []
+#             # for i in range(0, len(D['ssh_content'])):
+#             #     if "#" in D['ssh_content'][i] or D['ssh_content'][i] == '' or D['ssh_content'][i] == ' ':
+#             #         continue
+#             #     L.append(D['ssh_content'][i])
+#             # for i in L:
+#             #     print(i)
+#
+#             ssh.connect(hostname=ip,
+#                         port=22,
+#                         username='gs1801',
+#                         password='g53743001')
+#             # os.system("scp /home/benson/test10.sh gs1801@" + ip + ":/home/gs1801/")
+#             # 執行命令
+#             # stdin, stdout, stderr = ssh.exec_command("ls -l /home/gs1801;touch test7.py")
+#             # stdin, stdout, stderr = ssh.exec_command("touch test10.sh;echo '" + content + "' >> test10.sh;bash test10.sh")
+#             # print('test1')
+#             # print(stdout.read().decode())
+#             # print('test2')
+#             # print(stderr.read().decode())
+#
+#             for command in content:
+#                 stdin, stdout, stderr = ssh.exec_command(command)
+#             #
+#             #     # print(stdout.read().decode())
+#             #     # print('----------------------------------------')
+#             #     # print(stderr.read().decode())
+#             #
+#                 if stderr.read().decode():
+#                     L.append(0)
+#                     print('error')
+#                     socketio.emit('stderr', 'error')
+#                 else:
+#                     L.append(1)
+#                     print('success')
+#                     print(socketio)
+#                     socketio.emit('stdout', 'success')
+#
+#             print(L)
+#             #
+#             # item_list = ItemList()
+#             # item_list.ip = ip
+#             # item_list.pymysql = L[0]
+#             # item_list.eventlet = L[1]
+#             # datetime = dt.now()
+#             # item_list.datetime = datetime
+#             # db.session.add(item_list)
+#             # db.session.commit()
+#
+#             # 關閉連線
+#             ssh.close()
+#             return "建置結束!"
+#         except Exception as e:
+#             print(e)
+#             return e
+
+
+#拿取伺服器建置清單狀態的訪問路徑
+@main.route('/item_list/<ip>', methods=['POST', 'GET'])
+def item_list_views(ip):
+    username = session['uname']
+    if request.method == 'GET':
+        item_list = ItemList.query.filter_by(ip=ip).order_by(text('datetime desc')).first()
+        pymysql = item_list.pymysql
+        eventlet = item_list.eventlet
+        return jsonify(pymysql=pymysql, eventlet=eventlet)
+    else:
+        pass
+
+
+#過濾前端傳過來文件副檔名函數
+def allowed_file(filename):
+    return '.' in filename and \
+           filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
+
+
+#認證token的訪問路徑
+@main.route('/auth', methods=['POST', 'GET'])
+@jwt_required
+def auth_views():
+    if request.method == 'GET':
+        identity = get_jwt_identity()
+        print(identity)
+        return jsonify(identity=identity)
+
+
+
+
+# 退出的訪問路徑
+@main.route('/logout')
+def logout_views():
+    if 'token' in session and 'uname' in session:
+        # del session['id']
+        del session['uname']
+        del session['token']
+        # del session['status']
+    return redirect('/')
+
+
+

+ 187 - 0
BBend-Test-JWT/app/models.py

@@ -0,0 +1,187 @@
+# coding: utf-8
+from sqlalchemy import Column, DateTime, Integer, Numeric, String
+from flask_sqlalchemy import SQLAlchemy
+#使用Werkzeug的security加密
+from werkzeug.security import generate_password_hash,check_password_hash
+
+#與當前項目相關的模型文件,即所有的實體類在此編寫
+from manage import db
+
+class User(db.Model):
+    __tablename__ = 'user'
+
+    sn = db.Column(db.Integer, primary_key=True)
+    firstname = db.Column(db.String(30), nullable=False)
+    lastname = db.Column(db.String(30), nullable=False)
+    mail = db.Column(db.String(50), nullable=False)
+    phone = db.Column(db.String(20), nullable=False)
+    username = db.Column(db.String(30), nullable=False, unique=True)
+    password = db.Column(db.String(40), nullable=False)
+    status = db.Column(db.Integer, nullable=False, info='0:admin;1:new;2:old')
+    isActive = db.Column(db.Boolean, nullable=False, default=True)
+
+    purchase_info = db.relationship('PurchaseInfo', backref='user', uselist=False)
+
+    node_info = db.relationship('NodeInfo', backref='user', uselist=False)
+
+    farm_info = db.relationship('FarmInfo', backref='user', uselist=False)
+
+    permission = db.relationship('Permissions', backref='user', uselist=False)
+
+    node_imgs = db.relationship('NodeImage', backref='user', lazy='dynamic')
+
+    node_positions = db.relationship('NodePosition', backref='user', lazy='dynamic')
+
+    module_sn_numbers = db.relationship('ModuleSerialNumber', backref='user', lazy='dynamic')
+
+
+
+#哈希加密版本
+# class User(db.Model):
+#     __tablename__ = 'user'
+#
+#     sn = db.Column(db.Integer, primary_key=True)
+#     firstname = db.Column(db.String(30), nullable=False)
+#     lastname = db.Column(db.String(30), nullable=False)
+#     mail = db.Column(db.String(50), nullable=False)
+#     phone = db.Column(db.String(20), nullable=False)
+#     username = db.Column(db.String(30), nullable=False, unique=True)
+#     password = db.Column(db.Text, nullable=False)
+#     status = db.Column(db.Integer, nullable=False, info='0:admin;1:new;2:old')
+#     isActive = db.Column(db.Boolean, nullable=False, default=True)
+#
+#     purchase_info = db.relationship('PurchaseInfo', backref='user', uselist=False)
+#
+#     node_info = db.relationship('NodeInfo', backref='user', uselist=False)
+#
+#     farm_info = db.relationship('FarmInfo', backref='user', uselist=False)
+#
+#     permission = db.relationship('Permissions', backref='user', uselist=False)
+#
+#     node_imgs = db.relationship('NodeImage', backref='user', lazy='dynamic')
+#
+#     node_positions = db.relationship('NodePosition', backref='user', lazy='dynamic')
+#
+#     module_sn_numbers = db.relationship('ModuleSerialNumber', backref='user', lazy='dynamic')
+
+    # def __init__(self, *args, **kwargs):
+    #     username = kwargs.get('username')
+    #     password = kwargs.get('password')
+    #
+    #     self.username = username
+    #     self.password = generate_password_hash(password)
+    #
+    # # 这里的参数是hash过的参数以及原始传入hash
+    # def check_hash_password(self,raw_password):
+    #     result = check_password_hash(self.password, raw_password)
+    #     return result
+    #     # 得到验证結果  
+
+
+class PurchaseInfo(db.Model):
+    __tablename__ = 'purchase_info'
+
+    sn = db.Column(db.Integer, primary_key=True)
+    loc_length = db.Column(db.Text, nullable=False)
+    loc_width = db.Column(db.Text, nullable=False)
+    location = db.Column(db.Text, nullable=False)
+    monitor_num = db.Column(db.Integer, nullable=False)
+    connect = db.Column(db.Text, nullable=False)
+    user_id = db.Column(db.Integer, db.ForeignKey('user.sn'))
+    datetime = db.Column(db.DateTime, nullable=False)
+
+
+class NodeInfo(db.Model):
+    __tablename__ = 'node_info'
+
+    sn = db.Column(db.Integer, primary_key=True)
+    node_info = db.Column(db.Text, nullable=False)
+    user_id = db.Column(db.Integer, db.ForeignKey('user.sn'))
+
+
+class FarmInfo(db.Model):
+    __tablename__ = 'farm_info'
+
+    sn = db.Column(db.Integer, primary_key=True)
+    path = db.Column(db.Text, nullable=False, default='0')
+    location = db.Column(db.Text, nullable=False, default='0')
+    loc_lat = db.Column(db.Text, nullable=False, default='0')
+    loc_lng = db.Column(db.Text, nullable=False, default='0')
+    user_id = db.Column(db.Integer, db.ForeignKey('user.sn'))
+    datetime = db.Column(db.DateTime, nullable=False)
+
+class NodeImage(db.Model):
+    __tablename__ = 'node_img'
+
+    sn = db.Column(db.Integer, primary_key=True)
+    node_name = db.Column(db.String(10), nullable=False)
+    path = db.Column(db.Text, nullable=False, default='0')
+    user_id = db.Column(db.Integer, db.ForeignKey('user.sn'))
+    datetime = db.Column(db.DateTime, nullable=False)
+
+class NodePosition(db.Model):
+    __tablename__ = 'node_position'
+
+    sn = db.Column(db.Integer, primary_key=True)
+    node_name = db.Column(db.String(10), nullable=False)
+    pos_lat = db.Column(db.Text, nullable=False)
+    pos_lng = db.Column(db.Text, nullable=False)
+    user_id = db.Column(db.Integer, db.ForeignKey('user.sn'))
+    datetime = db.Column(db.DateTime, nullable=False)
+
+class ModuleSerialNumber(db.Model):
+    __tablename__ = 'module_sn_number'
+
+    sn = db.Column(db.Integer, primary_key=True)
+    module_name = db.Column(db.String(30), nullable=False)
+    sn_number = db.Column(db.Text, nullable=False)
+    user_id = db.Column(db.Integer, db.ForeignKey('user.sn'))
+    datetime = db.Column(db.DateTime, nullable=False)
+
+#權限表
+class Permissions(db.Model):
+    __tablename__ = 'permissions'
+
+    sn = db.Column(db.Integer, primary_key=True)
+    user_id = db.Column(db.Integer, db.ForeignKey('user.sn'))
+    add_domain = db.Column(db.Integer, nullable=False, default=0)
+    company_profile = db.Column(db.Integer, nullable=False, default=0)
+    product_info = db.Column(db.Integer, nullable=False, default=0)
+    erp = db.Column(db.Integer, nullable=False, default=0)
+    rma = db.Column(db.Integer, nullable=False, default=0)
+    download_data = db.Column(db.Integer, nullable=False, default=0)
+    gps = db.Column(db.Integer, nullable=False, default=0)
+    sensor = db.Column(db.Integer, nullable=False, default=0)
+    Actuator = db.Column(db.Integer, nullable=False, default=0)
+    diary_log = db.Column(db.Integer, nullable=False, default=0)
+    repair_log = db.Column(db.Integer, nullable=False, default=0)
+    set_permission = db.Column(db.Integer, nullable=False, default=0)
+    register = db.Column(db.Integer, nullable=False, default=0)
+    blacklist = db.Column(db.Integer, nullable=False, default=0)
+    back_manage = db.Column(db.Integer, nullable=False, default=0)
+    module_test = db.Column(db.Integer, nullable=False, default=0)
+
+class SensorList(db.Model):
+    __tablename__ = 'sensor_list'
+
+    sn = db.Column(db.Integer, primary_key=True)
+    ch_name = db.Column(db.String(20), nullable=False)
+    en_name = db.Column(db.String(20), nullable=False)
+    version = db.Column(db.String(10), nullable=False)
+    datetime = db.Column(db.DateTime, nullable=False)
+
+
+    #自定義序列化方法,方便在前端拿數據
+    def toDict(self):
+        return {'ch_name':self.ch_name, 'en_name':self.en_name, 'version':self.version}
+
+class ItemList(db.Model):
+    __tablename__ = 'item_list'
+
+    sn = db.Column(db.Integer, primary_key=True)
+    ip = db.Column(db.Text, nullable=False)
+    pymysql = db.Column(db.Integer, nullable=False)
+    eventlet = db.Column(db.Integer, nullable=False)
+    datetime = db.Column(db.DateTime, nullable=False)
+
+db.create_all()

+ 112 - 0
BBend-Test-JWT/app/static/css/registration.css

@@ -0,0 +1,112 @@
+        .img-fluid {
+            margin-top: 50px;
+        }
+
+        .text-center {
+            margin-top: 50px;
+        }
+
+        form {
+            margin-top: 50px;
+        }
+
+        form > div:last-child {
+            margin-top: 40px;
+        }
+
+        form > div:last-child input:last-child {
+            margin-left: 120px;
+        }
+
+        .btn-info {
+            width: 105px;
+            height: 43px;
+            background: #85BF31;
+            border: 1px solid #CFCFCF;
+            box-sizing: border-box;
+            border-radius: 5px;
+            color: #000000;
+        }
+
+        .wrong-info {
+            height: 20px;
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: normal;
+            font-size: 14px;
+            color: #FF0505;
+        }
+
+        @media(max-width:373px){
+            .col-2 {
+                display: none;
+            }
+        }
+
+        @media(max-width:577px){
+            form > div:last-child input:last-child {
+                margin-left: 0px;
+            }
+        }
+
+        @media(min-width:576px){
+
+        }
+
+         @media(min-width:768px){
+            .form-inline {
+                margin-left: 60px;
+            }
+            form > div:last-child {
+                margin-left: 60px;
+            }
+            .wrong-info {
+                margin-left: 50px;
+            }
+            #first {
+                margin-left: 70px;
+            }
+            #last {
+                margin-left: 71px;
+            }
+            #email {
+                margin-left: 108px;
+            }
+            #phone {
+                margin-left: 103px;
+            }
+            #usr {
+                margin-left: 68px;
+            }
+            #pwd {
+                margin-left: 81px;
+            }
+            #cpwd {
+                margin-left: 22px;
+            }
+
+         }
+
+         @media(min-width:991px){
+            .form-inline {
+                margin-left: 140px;
+            }
+            form > div:last-child {
+                margin-left: 150px;
+            }
+            .wrong-info {
+                margin-left: 140px;
+            }
+         }
+
+         @media(min-width:1200px){
+            .form-inline {
+                margin-left: 180px;
+            }
+             form > div:last-child {
+                margin-left: 190px;
+            }
+            .wrong-info {
+                margin-left: 170px;
+            }
+         }

+ 103 - 0
BBend-Test-JWT/app/static/css/reset_pwd1.css

@@ -0,0 +1,103 @@
+        .img-fluid {
+            margin-top: 50px;
+        }
+
+        h1 {
+            margin-top: 30px;
+        }
+
+        .descripe {
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: normal;
+            font-size: 18px;
+            line-height: 21px;
+        }
+
+        form {
+            margin-top: 50px;
+        }
+
+        form > div:last-child {
+            margin-top: 40px;
+        }
+
+        form > div:last-child input:last-child {
+            margin-left: 100px;
+        }
+
+        .btn-info {
+            width: 105px;
+            height: 43px;
+            background: #85BF31;
+            border: 1px solid #CFCFCF;
+            box-sizing: border-box;
+            border-radius: 5px;
+            color: #000000;
+        }
+
+        .wrong-info {
+            height: 20px;
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: normal;
+            font-size: 14px;
+            color: #FF0505;
+        }
+
+        @media(max-width:373px){
+            .col-2 {
+                display: none;
+            }
+        }
+
+        @media(max-width:577px){
+            form > div:last-child input:last-child {
+                margin-left: 0px;
+            }
+        }
+
+        @media(min-width:576px){
+            #email {
+                margin-left: 70px;
+            }
+            .form div:not(:first-child) {
+                margin-top: 20px;
+            }
+
+        }
+         @media(min-width:768px){
+            .form-inline {
+                margin-left: 50px;
+            }
+            form > div:last-child {
+                margin-left: 60px;
+            }
+            .wrong-info {
+                margin-left: 50px;
+            }
+         }
+
+         @media(min-width:991px){
+            .form-inline {
+                margin-left: 140px;
+            }
+            form > div:last-child {
+                margin-left: 150px;
+            }
+            .wrong-info {
+                margin-left: 140px;
+            }
+         }
+
+         @media(min-width:1200px){
+            .form-inline {
+                margin-left: 180px;
+            }
+             form > div:last-child {
+                margin-left: 190px;
+            }
+            .wrong-info {
+                margin-left: 170px;
+            }
+         }

+ 106 - 0
BBend-Test-JWT/app/static/css/reset_pwd2.css

@@ -0,0 +1,106 @@
+        .img-fluid {
+            margin-top: 50px;
+        }
+
+        h1 {
+            margin-top: 30px;
+        }
+
+        .descripe {
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: normal;
+            font-size: 18px;
+            line-height: 21px;
+        }
+
+        form {
+            margin-top: 50px;
+        }
+
+        form > div:last-child {
+            margin-top: 40px;
+        }
+
+        form > div:last-child input:last-child {
+            margin-left: 100px;
+        }
+
+        .btn-info {
+            width: 105px;
+            height: 43px;
+            background: #85BF31;
+            border: 1px solid #CFCFCF;
+            box-sizing: border-box;
+            border-radius: 5px;
+            color: #000000;
+        }
+
+        .wrong-info {
+            height: 20px;
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: normal;
+            font-size: 14px;
+            color: #FF0505;
+        }
+
+        @media(max-width:373px){
+            .col-2 {
+                display: none;
+            }
+        }
+
+        @media(max-width:577px){
+            form > div:last-child input:last-child {
+                margin-left: 0px;
+            }
+        }
+
+        @media(min-width:576px){
+            #new-pwd {
+                margin-left: 70px;
+            }
+            #confirm-pwd {
+                margin-left: 46px;
+            }
+            .form div:not(:first-child) {
+                margin-top: 20px;
+            }
+
+        }
+         @media(min-width:768px){
+            .form-inline {
+                margin-left: 50px;
+            }
+            form > div:last-child {
+                margin-left: 60px;
+            }
+            .wrong-info {
+                margin-left: 50px;
+            }
+         }
+
+         @media(min-width:991px){
+            .form-inline {
+                margin-left: 140px;
+            }
+            form > div:last-child {
+                margin-left: 150px;
+            }
+            .wrong-info {
+                margin-left: 140px;
+            }
+         }
+
+         @media(min-width:1200px){
+            .form-inline {
+                margin-left: 180px;
+            }
+             form > div:last-child {
+                margin-left: 190px;
+            }
+            .wrong-info {
+                margin-left: 170px;
+            }
+         }

+ 116 - 0
BBend-Test-JWT/app/static/css/sign_in.css

@@ -0,0 +1,116 @@
+        .img-fluid {
+            margin-top: 50px;
+        }
+
+        .text-center {
+            margin-top: 30px;
+        }
+
+        form {
+            margin-top: 50px;
+        }
+
+         .radio a {
+            text-decoration: none;
+            margin-left: 75px;
+        }
+
+        form > div:last-child {
+            margin-top: 40px;
+        }
+
+        form > div:last-child input:last-child {
+            margin-left: 100px;
+        }
+
+        .btn-info {
+            width: 105px;
+            height: 43px;
+            background: #85BF31;
+            border: 1px solid #CFCFCF;
+            box-sizing: border-box;
+            border-radius: 5px;
+            color: #000000;
+        }
+
+        .wrong-info {
+            height: 20px;
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: normal;
+            font-size: 14px;
+            color: #FF0505;
+        }
+
+        @media(max-width:373px){
+            .col-2 {
+                display: none;
+            }
+        }
+
+        @media(max-width:577px){
+            .radio a {
+                margin-left: 0px;
+                display: block;
+            }
+            form > div:last-child input:last-child {
+                margin-left: 0px;
+            }
+        }
+
+        @media(min-width:576px){
+            #usr {
+                margin-left: 70px;
+            }
+            #pwd {
+                margin-left: 43px;
+            }
+            .form div:not(:first-child) {
+                margin-top: 20px;
+            }
+
+        }
+         @media(min-width:768px){
+            .form-inline {
+                margin-left: 50px;
+            }
+            .radio {
+                margin-left: 50px;
+            }
+            form > div:last-child {
+                margin-left: 60px;
+            }
+            .wrong-info {
+                margin-left: 50px;
+            }
+         }
+
+         @media(min-width:991px){
+            .form-inline {
+                margin-left: 140px;
+            }
+            .radio {
+                margin-left: 140px;
+            }
+            form > div:last-child {
+                margin-left: 150px;
+            }
+            .wrong-info {
+                margin-left: 140px;
+            }
+         }
+
+         @media(min-width:1200px){
+            .form-inline {
+                margin-left: 180px;
+            }
+            .radio {
+                margin-left: 180px;
+            }
+             form > div:last-child {
+                margin-left: 190px;
+            }
+            .wrong-info {
+                margin-left: 170px;
+            }
+         }

TEMPAT SAMPAH
BBend-Test-JWT/app/static/farm_img/benson/2020731_200803.jpg


TEMPAT SAMPAH
BBend-Test-JWT/app/static/farm_img/benson/274205.jpg


TEMPAT SAMPAH
BBend-Test-JWT/app/static/farm_img/benson/Pasted_Image_2020-11-26_09-58-20.png


TEMPAT SAMPAH
BBend-Test-JWT/app/static/farm_img/benson/material-design-color-chart.png


TEMPAT SAMPAH
BBend-Test-JWT/app/static/farm_img/benson/psfi.jpg


TEMPAT SAMPAH
BBend-Test-JWT/app/static/farm_img/benson/rosgraph.png


TEMPAT SAMPAH
BBend-Test-JWT/app/static/farm_img/benson/screenshot.png


TEMPAT SAMPAH
BBend-Test-JWT/app/static/img/battery.png


TEMPAT SAMPAH
BBend-Test-JWT/app/static/img/logo_new.png


TEMPAT SAMPAH
BBend-Test-JWT/app/static/img/psfi.jpg


+ 100 - 0
BBend-Test-JWT/app/static/js/registration.js

@@ -0,0 +1,100 @@
+        function Login(){
+            window.location.href='/login';
+        };
+
+        $(function (){
+            var firstname = $("input[name='firstname']");
+            var lastname = $("input[name='lastname']");
+            var email = $("input[name='email']");
+            var phone = $("input[name='phone']");
+            var username = $("input[name='username']");
+            var password = $("input[name='password']");
+            var confirmpwd = $("input[name='confirmpwd']");
+            var status = false;
+            var form = $("form");
+
+            firstname.blur(function(){
+                var span = $("#firstname-span");
+                if(firstname.val() == ''){
+                    span.text("Field is requied");
+                    status = false;
+                }else{
+                    span.text("");
+                    status = true;
+                };
+            });
+
+            lastname.blur(function(){
+                var span = $("#lastname-span");
+                if(lastname.val() == ''){
+                    span.text("Field is requied");
+                    status = false;
+                }else{
+                    span.text("");
+                    status = true;
+                };
+            });
+
+            email.blur(function(){
+                var span = $("#email-span");
+                if(email.val().indexOf('@') == -1){
+                    span.text("Incorrect email address");
+                    status = false;
+                }else{
+                    span.text("");
+                    status = true;
+                    $.get('/check_email','email='+email.val(),function(resText){
+                        if(resText.errMsg){
+                            $("#firstname_span").text("This email is already registered");
+                            status = false;
+                        }else{
+                            $("#firstname_span").text("");
+                            status = true;
+                        };
+                    },'json');
+                };
+            });
+
+            phone.blur(function(){
+                var span = $("#phone-span");
+                if(phone.val().length < 8 || isNaN(phone.val()) == true){
+                    span.text("Wrong phone number");
+                    status = false;
+                }else{
+                    span.text("");
+                    status = true;
+                };
+            });
+
+            username.blur(function(){
+                $.get("/check_username","username="+username.val(),function(resText){
+                    if(resText.errMsg){
+                        $("#firstname-span").text("This username is already registered");
+                        status = false;
+                    }else{
+                        $("#firstname-span").text("");
+                        status = true;
+                    };
+                },'json');
+            });
+
+            confirmpwd.blur(function(){
+                var span = $("#password-span");
+                if(password.val() != confirmpwd.val()){
+                    span.text("Passwords does not match");
+                    status = false;
+                }else{
+                    span.text("");
+                    status = true;
+                };
+            });
+
+            form.submit(function(){
+                if((status == true) && (password.val() != '') && (confirmpwd.val() != '')){
+                    return true;
+                }else{
+                    alert("Please type your infomation");
+                    return false;
+                };
+            });
+        });

+ 3 - 0
BBend-Test-JWT/app/static/js/reset_pwd1.js

@@ -0,0 +1,3 @@
+function Login(){
+    window.location.href='/login';
+};

+ 3 - 0
BBend-Test-JWT/app/static/js/reset_pwd2.js

@@ -0,0 +1,3 @@
+function ResetPassword(){
+    window.location.href='/reset_password';
+};

+ 3 - 0
BBend-Test-JWT/app/static/js/sign_in.js

@@ -0,0 +1,3 @@
+function Registration(){
+    window.location.href='/register';
+};

+ 331 - 0
BBend-Test-JWT/app/templates/add_sensor.html

@@ -0,0 +1,331 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Aisky-Sixth</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+
+    <!-- 新 Bootstrap4 核心 CSS 文件 -->
+    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.1.0/css/bootstrap.min.css">
+
+    <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
+    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
+
+    <!-- popper.min.js 用于弹窗、提示、下拉菜单 -->
+    <script src="https://cdn.bootcss.com/popper.js/1.12.5/umd/popper.min.js"></script>
+
+    <!-- 最新的 Bootstrap4 核心 JavaScript 文件 -->
+    <script src="https://cdn.bootcss.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
+
+    <!--可用來建立使用者小圖示-->
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
+
+
+
+    <style>
+        body {
+	        margin:0;
+        }
+
+        .navbar-dark .navbar-nav .nav-link {
+            color: white;
+            cursor: pointer;
+	        text-decoration:none;
+            width: 130px;
+            height: 46px;
+        }
+
+        .nav-top {
+	        line-height:40px;
+	        background-color: #C4C4C4;
+        }
+
+        .website_title{
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: normal;
+            font-size: 30px;
+            color: #000000;
+        }
+
+        .navbar-nav > li{
+	        float: none;
+	        display: inline-block;
+	        width: 110px;
+            margin: 0 auto;
+            text-align: center;
+        }
+
+        .navbar-nav > li a{
+            font-size: 20px;
+        }
+
+        .main-page {
+            margin-top: 150px;
+        }
+
+        .page-title {
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: bold;
+            font-size: 36px;
+        }
+
+
+        .flex {
+            display: flex;
+            flex-direction: row;
+            flex-wrap: wrap;
+            justify-content: center;
+        }
+
+          .set-link {
+            display: inline-block;
+            width: 350px;
+            height: 100px;
+            line-height: 100px;
+            background: #008CBA;
+            border: 1px solid #CFCFCF;
+            box-sizing: border-box;
+            color: #FFFFFF;
+            border-radius: 10px;
+            font-size: 36px;
+
+        }
+
+        .page-bottom {
+            margin-top: 70px;
+        }
+
+        .form-control {
+            background: #008CBA;
+            border: 1px solid #CFCFCF;
+            box-sizing: border-box;
+            border-radius: 5px;
+            width: 120px;
+            height: 58px;
+            text-align: center;
+            line-height: 50px;
+            font-size:20px;
+            color: #FFFFFF;
+            display: inline-block;
+            cursor: pointer;
+        }
+
+        .fa{
+            display: inline-block;
+            font: normal normal normal 14px/1 FontAwesome;
+            font-size: inherit;
+            text-rendering: auto;
+            -webkit-font-smoothing: antialiased;
+        }
+
+        .fa-user-o:before{
+            content: "\f2c0";
+        }
+
+        button {
+            cursor: pointer;
+        }
+
+
+        @media(max-width:373px){
+            .card {
+                margin-right: 0px;
+            }
+        }
+
+        @media(max-width:577px){
+
+        }
+
+        @media(min-width:576px){
+
+
+        }
+         @media(min-width:768px){
+            .navbar-nav > li {
+                 margin-left: 0px;
+            }
+            .navbar-nav .li-block {
+                display:none;
+            }
+         }
+
+         @media(min-width:991px){
+            .navbar-nav > li {
+                 margin-left: 20px;
+            }
+            .navbar-nav .li-block {
+                display:none;
+            }
+         }
+
+         @media(min-width:1200px){
+            .navbar-nav > li {
+                 margin-left: 35px;
+            }
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 100px;
+            }
+         }
+
+         @media(min-width:1400px){
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 200px;
+            }
+
+         }
+
+
+         @media(min-width:1689px) {
+            .navbar-nav > li {
+                 margin-left: 50px;
+            }
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 500px;
+            }
+         }
+
+
+    </style>
+
+
+    <script>
+         //驗證token,如果不符合或過期就登出回登入頁
+         var str = localStorage.getItem('Hello');
+         $.ajax({
+                type: "GET",
+                url: "/auth",
+                headers: {'Authorization': 'Bearer ' + str},
+                success: function(result){
+                    console.log(result.identity);
+                },
+                error: function(result){
+                    window.location.href='/logout';
+                }
+         });
+
+        $(function(){
+            $("#add_btn").click(function (){
+                if($("#ch_name").val() == '' || $("#en_name").val() == '' || $("#version").val() == ''){
+                    alert("請輸入完整資訊!");
+                    return false;
+                };
+
+                var data = {"ch_name":$("#ch_name").val(), "en_name":$("#en_name").val(), "version":$("#version").val()};
+
+                $.ajax({
+                    url: '/add_sensor',
+                    type: 'post',
+                    data: data,
+                    dataType: 'text',
+                    success: function(msg){
+                        alert(msg);
+                        $("#ch_name").val('');
+                        $("#en_name").val('');
+                        $("#version").val('');
+                    },
+                    error: function(msg){
+                        alert(msg);
+                    },
+                });
+
+            });
+        });
+    </script>
+
+
+</head>
+<body>
+    <nav class="fixed-top">
+        <nav class="navbar navbar-expand-md nav-top justify-content-center">
+            <div>
+                <span class="website_title">新增感測器</span>
+            </div>
+        </nav>
+        <nav class="navbar navbar-expand-md bg-dark navbar-dark nav-bottom">
+            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
+                <span class="navbar-toggler-icon"></span>
+            </button>
+            <div class="collapse navbar-collapse" id="collapsibleNavbar">
+                <ul class="navbar-nav">
+                    <li class="nav-item">
+                        <a class="nav-link" href="/">首頁</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/incoming_check">進貨檢測</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/burn_program">感測器燒錄</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/modify_permissions">權限設置</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/add_sensor">新增感測器</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/add_server">伺服器建置</a>
+                    </li>
+                    <li class="li-block"></li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="#"><i class="fa fa-user-o"></i> {{params.username}}</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/logout">Logout</a>
+                    </li>
+                </ul>
+            </div>
+        </nav>
+    </nav>
+    <div class="main-page">
+        <div class="container-fluid">
+            <div class="row">
+                <div class="col flex" style="margin: auto; ">
+                    <form action="/add_sensor" method="post">
+                         <table class="table table-bordered" style="font-size:23px;margin-top:70px;">
+                            <tbody>
+                                <tr>
+                                    <td>1.</td>
+                                    <td>請輸入要新增感測器的中文名:</td>
+                                    <td>
+                                        <input type="text" id="ch_name" name="ch_name">
+                                    </td>
+                                </tr>
+                                <tr>
+                                    <td>2.</td>
+                                    <td>請輸入要新增感測器的英文名:</td>
+                                    <td>
+                                        <input type="text" id="en_name" name="en_name">
+                                    </td>
+                                </tr>
+                                <tr>
+                                    <td>3.</td>
+                                    <td>請輸入版本號:</td>
+                                    <td>
+                                        <input type="text" id="version" name="version" placeholder="例:v1.0">
+                                    </td>
+                                </tr>
+                            </tbody>
+                        </table>
+                        <div class="row page-bottom">
+                            <div class="col"></div>
+                            <div class="col-xl-8 col-lg-8 col-md-8 col-sm-10 col-xs-10" style="text-align:center;">
+                                <div class="form-group">
+                                    <input type="reset" class="form-control" value="重設" style="margin-right:70px;">
+                                    <input id="add_btn" type="button" class="form-control" value="送出">
+                                </div>
+                            </div>
+                            <div class="col"></div>
+                        </div>
+                    </form>
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>

+ 708 - 0
BBend-Test-JWT/app/templates/add_server.html

@@ -0,0 +1,708 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Aisky-Sixth</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+
+    <!-- 新 Bootstrap4 核心 CSS 文件 -->
+    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.1.0/css/bootstrap.min.css">
+
+    <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
+    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
+
+    <!-- popper.min.js 用于弹窗、提示、下拉菜单 -->
+    <script src="https://cdn.bootcss.com/popper.js/1.12.5/umd/popper.min.js"></script>
+
+    <!-- 最新的 Bootstrap4 核心 JavaScript 文件 -->
+    <script src="https://cdn.bootcss.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
+
+    <!--可用來建立使用者小圖示-->
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
+
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.dev.js"></script>
+
+<!--    <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>-->
+
+<!--    <script src="https://cdn.socket.io/4.0.1/socket.io.min.js" integrity="sha384-LzhRnpGmQP+lOvWruF/lgkcqD+WDVt9fU3H4BWmwP5u5LTmkUGafMcpZKNObVMLU" crossorigin="anonymous"></script>-->
+
+
+
+    <style>
+        body {
+	        margin:0;
+        }
+
+        .navbar-dark .navbar-nav .nav-link {
+            color: white;
+            cursor: pointer;
+	        text-decoration:none;
+            width: 130px;
+            height: 46px;
+        }
+
+        .nav-top {
+	        line-height:40px;
+	        background-color: #C4C4C4;
+        }
+
+        .website_title{
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: normal;
+            font-size: 30px;
+            color: #000000;
+        }
+
+        .navbar-nav > li{
+	        float: none;
+	        display: inline-block;
+	        width: 110px;
+            margin: 0 auto;
+            text-align: center;
+        }
+
+        .navbar-nav > li a{
+            font-size: 20px;
+        }
+
+        .main-page {
+            margin-top: 150px;
+        }
+
+        .page-title {
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: bold;
+            font-size: 36px;
+        }
+
+
+        .flex {
+            display: flex;
+            flex-direction: row;
+            flex-wrap: wrap;
+            justify-content: center;
+        }
+
+          .set-link {
+            display: inline-block;
+            width: 350px;
+            height: 100px;
+            line-height: 100px;
+            background: #008CBA;
+            border: 1px solid #CFCFCF;
+            box-sizing: border-box;
+            color: #FFFFFF;
+            border-radius: 10px;
+            font-size: 36px;
+
+        }
+
+        .fa{
+            display: inline-block;
+            font: normal normal normal 14px/1 FontAwesome;
+            font-size: inherit;
+            text-rendering: auto;
+            -webkit-font-smoothing: antialiased;
+        }
+
+        .fa-user-o:before{
+            content: "\f2c0";
+        }
+
+        button {
+            cursor: pointer;
+        }
+
+
+        @media(max-width:373px){
+            .card {
+                margin-right: 0px;
+            }
+        }
+
+        @media(max-width:577px){
+
+        }
+
+        @media(min-width:576px){
+
+
+        }
+         @media(min-width:768px){
+            .navbar-nav > li {
+                 margin-left: 0px;
+            }
+            .navbar-nav .li-block {
+                display:none;
+            }
+         }
+
+         @media(min-width:991px){
+            .navbar-nav > li {
+                 margin-left: 20px;
+            }
+            .navbar-nav .li-block {
+                display:none;
+            }
+         }
+
+         @media(min-width:1200px){
+            .navbar-nav > li {
+                 margin-left: 35px;
+            }
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 100px;
+            }
+         }
+
+         @media(min-width:1400px){
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 200px;
+            }
+
+         }
+
+
+         @media(min-width:1689px) {
+            .navbar-nav > li {
+                 margin-left: 50px;
+            }
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 500px;
+            }
+         }
+
+
+    </style>
+
+		<script>
+<!--            //驗證token,如果不符合或過期就登出回登入頁-->
+<!--            var str = localStorage.getItem('Hello');-->
+<!--            $.ajax({-->
+<!--                type: "GET",-->
+<!--                url: "/auth",-->
+<!--                headers: {'Authorization': 'Bearer ' + str},-->
+<!--                success: function(result){-->
+<!--                    console.log(result.identity);-->
+<!--                },-->
+<!--                error: function(result){-->
+<!--                    window.location.href='/logout';-->
+<!--                }-->
+<!--            });-->
+
+
+
+
+            $(function(){
+
+
+
+                var namespace = '/test_conn';
+                var url = 'http://127.0.0.1';
+                var port = '5000';
+                var socket = io.connect(url + ':' + port + namespace);
+
+                socket.on('connect', function() {
+                    socket.emit('connect_event', {data: 'connected!'});
+                });
+
+                socket.on('user-confirm', function(msg) {
+                    console.log(msg);
+                    if(msg == 'pass'){
+                        var item = document.getElementById('python3.8-status');
+                        item.style.width = '2%';
+                        item.innerText = '2%';
+                        timer_python38 = window.setInterval("AddBarIndex('python3.8-status')", 2000);
+                    };
+                });
+
+                socket.on('stdout', function(msg) {
+                    if(msg.indexOf('python3.8') != -1){
+                        ItemInstallSuccess(timer_python38, 'python3.8');
+                        timer_python3_pip = window.setInterval("AddBarIndex('python3-pip-status')", 2000);
+                    };
+
+                    if(msg.indexOf('python3-pip') != -1){
+                        ItemInstallSuccess(timer_python3_pip, 'python3-pip');
+                        timer_git = window.setInterval("AddBarIndex('git-status')", 2000);
+                    };
+
+                    if(msg.indexOf('git') != -1){
+                        ItemInstallSuccess(timer_git, 'git');
+                        timer_wget = window.setInterval("AddBarIndex('wget-status')", 2000);
+                    };
+
+                    if(msg.indexOf('wget') != -1){
+                        ItemInstallSuccess(timer_wget, 'wget');
+                        timer_grep = window.setInterval("AddBarIndex('grep-status')", 2000);
+                    };
+
+                    if(msg.indexOf('grep') != -1){
+                        ItemInstallSuccess(timer_grep, 'grep');
+                        timer_tasksel = window.setInterval("AddBarIndex('tasksel-status')", 2000);
+                    };
+
+                    if(msg.indexOf('tasksel') != -1){
+                        ItemInstallSuccess(timer_tasksel, 'tasksel');
+                        timer_lamp_server = window.setInterval("AddBarIndex('lamp-server-status')", 2000);
+                    };
+
+                    if(msg.indexOf('lamp-server') != -1){
+                        ItemInstallSuccess(timer_lamp_server, 'lamp-server');
+                        timer_phpMyAdmin510_all_languages = window.setInterval("AddBarIndex('phpMyAdmin-5.1.0-all-languages.tar.gz-status')", 2000);
+                    };
+
+<!--                    if(msg.indexOf('phpMyAdmin-5.1.0-all-languages.tar.gz') != -1){-->
+<!--                        ItemInstallSuccess(timer_phpMyAdmin510_all_languages, 'phpMyAdmin-5.1.0-all-languages.tar.gz');-->
+<!--                        timer_openssl = window.setInterval("AddBarIndex('openssl-status')", 2000);-->
+<!--                    };-->
+
+                    if(msg.indexOf('install phpmyadmin done') != -1){
+                        ItemInstallSuccess(timer_phpMyAdmin510_all_languages, 'phpMyAdmin-5.1.0-all-languages.tar.gz');
+                        timer_openssl = window.setInterval("AddBarIndex('openssl-status')", 2000);
+                    };
+
+                    if(msg.indexOf('openssl') != -1){
+                        ItemInstallSuccess(timer_openssl, 'openssl');
+                        timer_php_common = window.setInterval("AddBarIndex('php-common-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php-common') != -1){
+                        ItemInstallSuccess(timer_php_common, 'php-common');
+                        timer_php_curl = window.setInterval("AddBarIndex('php-curl-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php-curl') != -1){
+                        ItemInstallSuccess(timer_php_curl, 'php-curl');
+                        timer_php_json = window.setInterval("AddBarIndex('php-json-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php-json') != -1){
+                        ItemInstallSuccess(timer_php_json, 'php-json');
+                        timer_php_mbstring = window.setInterval("AddBarIndex('php-mbstring')", 2000);
+                    };
+
+                    if(msg.indexOf('php-mbstring') != -1){
+                        ItemInstallSuccess(timer_php_mbstring, 'php-mbstring');
+                        timer_php_mysql = window.setInterval("AddBarIndex('php-mysql')", 2000);
+                    };
+
+                    if(msg.indexOf('php-mysql') != -1){
+                        ItemInstallSuccess(timer_php_mysql, 'php-mysql');
+                        timer_php_xml = window.setInterval("AddBarIndex('php-xml-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php-xml') != -1){
+                        ItemInstallSuccess(timer_php_xml, 'php-xml');
+                        timer_php_zip = window.setInterval("AddBarIndex('php-zip-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php-zip') != -1){
+                        ItemInstallSuccess(timer_php_zip, 'php-zip');
+                        timer_php72_mbstring = window.setInterval("AddBarIndex('php7.2-mbstring-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php7.2-mbstring') != -1){
+                        ItemInstallSuccess(timer_php72_mbstring, 'php7.2-mbstring');
+                        timer_php72_xml = window.setInterval("AddBarIndex('php7.2-xml-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php7.2-xml') != -1){
+                        ItemInstallSuccess(timer_php72_xml, 'php7.2-xml');
+                        timer_php72_mysql = window.setInterval("AddBarIndex('php7.2-mysql-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php7.2-mysql') != -1){
+                        ItemInstallSuccess(timer_php72_mysql, 'php7.2-mysql');
+                        timer_php72_common = window.setInterval("AddBarIndex('php7.2-common-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php7.2-common') != -1){
+                        ItemInstallSuccess(timer_php72_common, 'php7.2-common');
+                        timer_php72_curl = window.setInterval("AddBarIndex('php7.2-curl-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php7.2-curl') != -1){
+                        ItemInstallSuccess(timer_php72_curl, 'php7.2-curl');
+                        timer_php72_json = window.setInterval("AddBarIndex('php7.2-json-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php7.2-json') != -1){
+                        ItemInstallSuccess(timer_php72_json, 'php7.2-json');
+                        timer_php72_zip = window.setInterval("AddBarIndex('php7.2-zip-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php7.2-zip') != -1){
+                        ItemInstallSuccess(timer_php72_zip, 'php7.2-zip');
+                        timer_service_apache2 = window.setInterval("AddBarIndex('service-apache2-start-status')", 2000);
+                    };
+
+                    if(msg.indexOf('service apache2 start') != -1){
+                        ItemInstallSuccess(timer_service_apache2, 'service-apache2-start');
+                        timer_setting_mysql = window.setInterval("AddBarIndex('setting-mysql-status')", 2000);
+                    };
+                    console.log(msg);
+                    console.log('test1');
+                });
+                socket.on('stderr', function(msg) {
+                    if(msg.indexOf('python3.8') != -1){
+                        ItemInstallFail(timer_python38, 'python3.8');
+                        timer_python3_pip = window.setInterval("AddBarIndex('python3-pip-status')", 2000);
+                    };
+
+                    if(msg.indexOf('python3-pip') != -1){
+                        ItemInstallFail(timer_python3_pip, 'python3-pip');
+                        timer_git = window.setInterval("AddBarIndex('git-status')", 2000);
+                    };
+
+                    if(msg.indexOf('git') != -1){
+                        ItemInstallFail(timer_git, 'git');
+                        timer_wget = window.setInterval("AddBarIndex('wget-status')", 2000);
+                    };
+
+                    if(msg.indexOf('wget') != -1){
+                        ItemInstallFail(timer_wget, 'wget');
+                        timer_grep = window.setInterval("AddBarIndex('grep-status')", 2000);
+                    };
+
+                    if(msg.indexOf('grep') != -1){
+                        ItemInstallFail(timer_grep, 'grep');
+                        timer_tasksel = window.setInterval("AddBarIndex('tasksel-status')", 2000);
+                    };
+
+                    if(msg.indexOf('tasksel') != -1){
+                        ItemInstallFail(timer_tasksel, 'tasksel');
+                        timer_lamp_server = window.setInterval("AddBarIndex('lamp-server-status')", 2000);
+                    };
+
+                    if(msg.indexOf('lamp-server') != -1){
+                        ItemInstallFail(timer_lamp_server, 'lamp-server');
+                        timer_phpMyAdmin = window.setInterval("AddBarIndex('phpMyAdmin-5.1.0-all-languages.tar.gz-status')", 2000);
+                    };
+
+<!--                    if(msg.indexOf('phpMyAdmin-5.1.0-all-languages.tar.gz') != -1){-->
+<!--                        ItemInstallFail(timer_phpMyAdmin, 'phpMyAdmin-5.1.0-all-languages.tar.gz');-->
+<!--                        timer_openssl = window.setInterval("AddBarIndex('openssl-status')", 2000);-->
+<!--                    };-->
+
+                    if(msg.indexOf('openssl') != -1){
+                        ItemInstallFail(timer_openssl, 'openssl');
+                        timer_php_common = window.setInterval("AddBarIndex('php-common-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php-common') != -1){
+                        ItemInstallFail(timer_php_common, 'php-common');
+                        timer_php_curl = window.setInterval("AddBarIndex('php-curl-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php-curl') != -1){
+                        ItemInstallFail(timer_php_curl, 'php-curl');
+                        timer_php_json = window.setInterval("AddBarIndex('php-json-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php-json') != -1){
+                        ItemInstallFail(timer_php_json, 'php-json');
+                        timer_php_mbstring = window.setInterval("AddBarIndex('php-mbstring')", 2000);
+                    };
+
+                    if(msg.indexOf('php-mbstring') != -1){
+                        ItemInstallFail(timer_php_mbstring, 'php-mbstring');
+                        timer_php_mysql = window.setInterval("AddBarIndex('php-mysql')", 2000);
+                    };
+
+                    if(msg.indexOf('php-mysql') != -1){
+                        ItemInstallFail(timer_php_mysql, 'php-mysql');
+                        timer_php_xml = window.setInterval("AddBarIndex('php-xml-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php-xml') != -1){
+                        ItemInstallFail(timer_php_xml, 'php-xml');
+                        timer_php_zip = window.setInterval("AddBarIndex('php-zip-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php-zip') != -1){
+                        ItemInstallFail(timer_php_zip, 'php-zip');
+                        timer_php72_mbstring = window.setInterval("AddBarIndex('php7.2-mbstring-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php7.2-mbstring') != -1){
+                        ItemInstallFail(timer_php72_mbstring, 'php7.2-mbstring');
+                        timer_php72_xml = window.setInterval("AddBarIndex('php7.2-xml-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php7.2-xml') != -1){
+                        ItemInstallFail(timer_php72_xml, 'php7.2-xml');
+                        timer_php72_mysql = window.setInterval("AddBarIndex('php7.2-mysql-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php7.2-mysql') != -1){
+                        ItemInstallFail(timer_php72_mysql, 'php7.2-mysql');
+                        timer_php72_common = window.setInterval("AddBarIndex('php7.2-common-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php7.2-common') != -1){
+                        ItemInstallFail(timer_php72_common, 'php7.2-common');
+                        timer_php72_curl = window.setInterval("AddBarIndex('php7.2-curl-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php7.2-curl') != -1){
+                        ItemInstallFail(timer_php72_curl, 'php7.2-curl');
+                        timer_php72_json = window.setInterval("AddBarIndex('php7.2-json-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php7.2-json') != -1){
+                        ItemInstallFail(timer_php72_json, 'php7.2-json');
+                        timer_php72_zip = window.setInterval("AddBarIndex('php7.2-zip-status')", 2000);
+                    };
+
+                    if(msg.indexOf('php7.2-zip') != -1){
+                        ItemInstallFail(timer_php72_zip, 'php7.2-zip');
+                        timer_service_apache2 = window.setInterval("AddBarIndex('service-apache2-start-status')", 2000);
+                    };
+
+                    if(msg.indexOf('service apache2 start') != -1){
+                        ItemInstallFail(timer_service_apache2, 'service-apache2-start');
+                        timer_setting_mysql = window.setInterval("AddBarIndex('setting-mysql-status')", 2000);
+                    };
+                    console.log(msg);
+                    console.log('test2');
+                });
+            });
+
+
+
+
+
+
+        </script>
+</head>
+<body>
+    <nav class="fixed-top">
+        <nav class="navbar navbar-expand-md nav-top justify-content-center">
+            <div>
+                <span class="website_title">伺服器建置</span>
+            </div>
+        </nav>
+        <nav class="navbar navbar-expand-md bg-dark navbar-dark nav-bottom">
+            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
+                <span class="navbar-toggler-icon"></span>
+            </button>
+            <div class="collapse navbar-collapse" id="collapsibleNavbar">
+                <ul class="navbar-nav">
+                    <li class="nav-item">
+                        <a class="nav-link" href="/">首頁</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/incoming_check">進貨檢測</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/burn_program">感測器燒錄</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/modify_permissions">權限設置</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/add_sensor">新增感測器</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/add_server">伺服器建置</a>
+                    </li>
+                    <li class="li-block"></li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="#"><i class="fa fa-user-o"></i> {{params.username}}</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/logout">Logout</a>
+                    </li>
+                </ul>
+            </div>
+        </nav>
+    </nav>
+    <div class="main-page">
+        <div class="container">
+            <div class="row">
+                <div class="col" style="margin: auto; ">
+                    <table  class="table table-bordered" style="font-size:23px;margin-top:30px;">
+                        <tbody>
+                            <tr>
+                                <td>1.請輸入您的IP位置:</td>
+                                <td><input type="text" name="user_ip"></td>
+                            </tr>
+                            <tr>
+                                <td>2.請輸入您的username:</td>
+                                <td><input type="text" name="user_username"></td>
+                            </tr>
+                            <tr>
+                                <td>3.請輸入您的password:</td>
+                                <td><input type="password" name="user_password"></td>
+                            </tr>
+                        </tbody>
+                    </table>
+                    <div class="text-center">
+                        <input type="button" value="建置" name="add_server" style="cursor:pointer;" onclick="AddServer()">
+                    </div>
+                    <div class="text-center" id="addServer-status" style="margin-top:30px;color:red;visibility:hidden;">
+                        <h2>伺服器建置中...</h2>
+                    </div>
+                    <div>
+                        <h1>Item install status</h1>
+                        <table  class="table table-bordered" style="font-size:23px;margin-top:30px;">
+                            <tbody>
+                                <tr>
+                                    <th>Item</th>
+                                    <th>Status</th>
+                                </tr>
+                                {% for item in params.L %}
+                                    <tr>
+                                        <td>{{loop.index}}.{{item}}</td>
+                                        <td>
+                                            <div class="progress" style="height:35px;">
+                                                <div id="{{item}}-status" name="{{item}}-status" class="progress-bar progress-bar-striped" style="width:0%;height:35px;font-size:20px;color:black;text-align:center;">0%</div>
+                                            </div>
+                                        </td>
+                                    </tr>
+                                {% endfor %}
+<!--                                <tr>-->
+<!--                                    <td>1.pymysql</td>-->
+<!--&lt;!&ndash;                                    <td><span name="pymysql-status"></span></td>&ndash;&gt;-->
+<!--                                    <td>-->
+<!--                                        <div class="progress" style="height:35px;">-->
+<!--                                            <div id="pymysql-status" class="progress-bar progress-bar-striped" style="width:0%;height:35px;font-size:20px;color:black;text-align:center;">0%</div>-->
+<!--                                        </div>-->
+<!--                                    </td>-->
+<!--                                </tr>-->
+<!--                                <tr>-->
+<!--                                    <td>2.eventlet</td>-->
+<!--&lt;!&ndash;                                    <td><span name="eventlet-status"></span></td>&ndash;&gt;-->
+<!--                                    <td>-->
+<!--                                        <div class="progress" style="height:35px;">-->
+<!--                                            <div id="eventlet-status" class="progress-bar progress-bar-striped" style="width:0%;height:35px;font-size:20px;color:black;text-align:center;">0%</div>-->
+<!--                                        </div>-->
+<!--                                    </td>-->
+<!--                                </tr>-->
+<!--                                <tr>-->
+<!--                                    <td>3.flask</td>-->
+<!--&lt;!&ndash;                                    <td><span name="eventlet-status"></span></td>&ndash;&gt;-->
+<!--                                    <td>-->
+<!--                                        <div class="progress" style="height:35px;">-->
+<!--                                            <div id="flask-status" class="progress-bar progress-bar-striped" style="width:0%;height:35px;font-size:20px;color:black;text-align:center;">0%</div>-->
+<!--                                        </div>-->
+<!--                                    </td>-->
+<!--                                </tr>-->
+                            </tbody>
+                        </table>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+    <script>
+                var timer_python38 = 0;
+                var timer_python3_pip = 0;
+                var timer_git = 0;
+                var timer_wget = 0;
+                var timer_grep = 0;
+                var timer_tasksel = 0;
+                var timer_lamp_server = 0;
+                var timer_phpMyAdmin = 0;
+                var timer_openssl = 0;
+                var timer_php_common = 0;
+                var timer_php_curl = 0;
+                var timer_php_json = 0;
+                var timer_php_mbstring = 0;
+                var timer_php_mysql = 0;
+                var timer_php_xml = 0;
+                var timer_php_zip = 0;
+                var timer_php72_mbstring = 0;
+                var timer_php72_xml = 0;
+                var timer_php72_mysql = 0;
+                var timer_php72_common = 0;
+                var timer_php72_curl = 0;
+                var timer_php72_json = 0;
+                var timer_php72_zip = 0;
+                var timer_service_apache2 = 0;
+                var timer_setting_mysql = 0;
+                var timer_paho_mqtt = 0;
+                var timer_mosquitto = 0;
+                var timer_mqtt_server = 0;
+                var timer_watchdog = 0;
+                var timer_golang = 0;
+                var timer_Git_server = 0;
+                var timer_flask = 0;
+                var timer_Flask_SQLAlchemy = 0;
+                var timer_pymysql = 0;
+                var timer_flask_mqtt = 0;
+                var timer_flask_migrate = 0;
+                var timer_flask_jwt_extended = 0;
+                var timer_numpy = 0;
+                var timer_pandas = 0;
+                var timer_opencv_python = 0;
+                var timer_BeautifulSoup4 = 0;
+                var timer_selenium = 0;
+                var timer_geocoder = 0;
+                var timer_AP = 0;
+                var timer_chrony_ntpdate = 0;
+                var timer_deb_ros_packages_and_keyserver = 0;
+                var timer_update = 0;
+                var timer_upgrade = 0;
+                var timer_ros_melodic_desktop_full = 0;
+                var timer_ros_melodic_rqt = 0;
+                var timer_pythonrosdep = 0;
+                var timer_python_rosinstall = 0;
+                var timer_ROS = 0;
+
+            function AddBarIndex(obj){
+                var item = document.getElementById(obj);
+                //因假設元素id內有.或是空格的使用jQuery選擇器會找不到,所以改成用js的節點來設置
+                //[0].style.width 讓width顯示為%值,使用css.('width')會顯示px
+                //var width = obj[0].style.width;
+                var width = item.style.width;
+                var current_width = width.substring(0, width.length-1);
+                item.style.width = Number(current_width) + 2 + '%';
+                item.innerText = Number(current_width) + 2 + '%';
+            };
+
+            function AddServer(){
+                //var item = document.getElementById('python3.8-status');
+                //item.style.width = '2%';
+                //item.innerText = '2%';
+                //timer_python38 = window.setInterval("AddBarIndex('python3.8-status')", 2000);
+                $("#addServer-status").css('visibility','visible');
+                var ip = $("input[name=user_ip]").val();
+                var username = $("input[name=user_username]").val();
+                var password = $("input[name=user_password]").val();
+                var json = {"ip":ip, "username":username, "password":password};
+                $.post('/add_server', json, function(resText){
+                    $("#addServer-status").css('visibility','hidden');
+                    if(resText == 'Authentication failed.'){
+                        resText = '您輸入的密碼有誤,請重新輸入!';
+                        $("input[name=user_ip]").val('');
+                        $("input[name=user_username]").val('');
+                        $("input[name=user_password]").val('');
+                    };
+                    alert(resText);
+                }, 'text');
+            };
+
+            function ItemInstallSuccess(timer_item, item_name){
+                eval('clearInterval(' + timer_item + ')');
+                var item = document.getElementById(item_name + '-status');
+                item.style.width = '100%';
+                item.innerText = '100%';
+            };
+
+            function ItemInstallFail(timer_item, item_name){
+                eval('clearInterval(' + timer_item + ')');
+                var item = document.getElementById(item_name + '-status');
+                item.style.width = '0%';
+                item.innerText = 'Fail';
+                item.style.color = 'red';
+            };
+    </script>
+</html>

+ 336 - 0
BBend-Test-JWT/app/templates/burn_program.html

@@ -0,0 +1,336 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Aisky-Sixth</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+
+    <!-- 新 Bootstrap4 核心 CSS 文件 -->
+    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.1.0/css/bootstrap.min.css">
+
+    <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
+    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
+
+    <!-- popper.min.js 用于弹窗、提示、下拉菜单 -->
+    <script src="https://cdn.bootcss.com/popper.js/1.12.5/umd/popper.min.js"></script>
+
+    <!-- 最新的 Bootstrap4 核心 JavaScript 文件 -->
+    <script src="https://cdn.bootcss.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
+
+    <!--可用來建立使用者小圖示-->
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
+
+
+
+    <style>
+        body {
+	        margin:0;
+        }
+
+        .navbar-dark .navbar-nav .nav-link {
+            color: white;
+            cursor: pointer;
+	        text-decoration:none;
+            width: 130px;
+            height: 46px;
+        }
+
+        .nav-top {
+	        line-height:40px;
+	        background-color: #C4C4C4;
+        }
+
+        .website_title{
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: normal;
+            font-size: 30px;
+            color: #000000;
+        }
+
+        .navbar-nav > li{
+	        float: none;
+	        display: inline-block;
+	        width: 110px;
+            margin: 0 auto;
+            text-align: center;
+        }
+
+        .navbar-nav > li a{
+            font-size: 20px;
+        }
+
+        .main-page {
+            margin-top: 150px;
+        }
+
+        .page-title {
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: bold;
+            font-size: 36px;
+        }
+
+
+        .flex {
+            display: flex;
+            flex-direction: row;
+            flex-wrap: wrap;
+            justify-content: center;
+        }
+
+          .set-link {
+            display: inline-block;
+            width: 200px;
+            height: 70px;
+            line-height: 70px;
+            background: #008CBA;
+            border: 1px solid #CFCFCF;
+            box-sizing: border-box;
+            color: #FFFFFF;
+            border-radius: 10px;
+            font-size: 25px;
+
+        }
+
+        .fa{
+            display: inline-block;
+            font: normal normal normal 14px/1 FontAwesome;
+            font-size: inherit;
+            text-rendering: auto;
+            -webkit-font-smoothing: antialiased;
+        }
+
+        .fa-user-o:before{
+            content: "\f2c0";
+        }
+
+        button {
+            cursor: pointer;
+        }
+
+
+        @media(max-width:373px){
+            .card {
+                margin-right: 0px;
+            }
+        }
+
+        @media(max-width:577px){
+
+        }
+
+        @media(min-width:576px){
+
+
+        }
+         @media(min-width:768px){
+            .navbar-nav > li {
+                 margin-left: 0px;
+            }
+            .navbar-nav .li-block {
+                display:none;
+            }
+         }
+
+         @media(min-width:991px){
+            .navbar-nav > li {
+                 margin-left: 20px;
+            }
+            .navbar-nav .li-block {
+                display:none;
+            }
+         }
+
+         @media(min-width:1200px){
+            .navbar-nav > li {
+                 margin-left: 35px;
+            }
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 100px;
+            }
+         }
+
+         @media(min-width:1400px){
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 200px;
+            }
+
+         }
+
+
+         @media(min-width:1689px) {
+            .navbar-nav > li {
+                 margin-left: 50px;
+            }
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 500px;
+            }
+         }
+
+
+    </style>
+
+        <style>
+        	html, body, #map-canvas{
+        	    width:100%;
+        	    height: 100%;
+        	}
+        </style>
+
+		<script>
+		    //燒錄程式函數
+            function BurnProgram(en_name, ch_name){
+                if(!confirm("你確定要燒錄" + ch_name + "嗎?")){
+                    return false;
+                };
+
+                $.post('/burn_program',en_name,function(resText){
+                    if(resText.status){
+                        alert("燒錄成功!");
+                    };
+                },'json');
+            };
+
+            //驗證token,如果不符合或過期就登出回登入頁
+            var str = localStorage.getItem('Hello');
+            $.ajax({
+                type: "GET",
+                url: "/auth",
+                headers: {'Authorization': 'Bearer ' + str},
+                success: function(result){
+                    console.log(result.identity);
+                },
+                error: function(result){
+                    window.location.href='/logout';
+                }
+            });
+
+            $(function(){
+                var sensor_list = $("#sensor_list");
+                var html = '';
+
+                $.each({{params.sensor_list|tojson}},function(index, obj){
+                    html += '<div class="col-xl-2  col-lg-2 col-md-2 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">';
+                    html += '    <div class="page-title text-center">';
+                    html += '        <button class="set-link" name="' + obj.en_name + '" type="button" onclick="BurnProgram(' + '\'' + obj.en_name + '\',\'' + obj.ch_name + ' ' + obj.version + '\')">' + obj.ch_name + ' ' + obj.version + '</button>';
+                    html += '    </div>';
+                    html += '</div>';
+                });
+
+                sensor_list.html(html);
+            });
+
+        </script>
+</head>
+<body>
+    <nav class="fixed-top">
+        <nav class="navbar navbar-expand-md nav-top justify-content-center">
+            <div>
+                <span class="website_title">感測器燒錄</span>
+            </div>
+        </nav>
+        <nav class="navbar navbar-expand-md bg-dark navbar-dark nav-bottom">
+            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
+                <span class="navbar-toggler-icon"></span>
+            </button>
+            <div class="collapse navbar-collapse" id="collapsibleNavbar">
+                <ul class="navbar-nav">
+                    <li class="nav-item">
+                        <a class="nav-link" href="/">首頁</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/incoming_check">進貨檢測</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/burn_program">感測器燒錄</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/modify_permissions">權限設置</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/add_sensor">新增感測器</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/add_server">伺服器建置</a>
+                    </li>
+                    <li class="li-block"></li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="#"><i class="fa fa-user-o"></i> {{params.username}}</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/logout">Logout</a>
+                    </li>
+                </ul>
+            </div>
+        </nav>
+    </nav>
+    <div class="main-page">
+        <div class="container-fluid">
+            <div class="row">
+                <div class="col-12 text-center"><h3 style="color:red;">請點擊以下感測器進行燒錄</h3></div>
+                <div id="sensor_list" class="col flex" style="margin: auto; ">
+                    <!--<div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">-->
+                        <!--<div class="page-title text-center">-->
+                            <!--<button class="set-link" name="airTem" type="button" onclick="BurnProgram('airTem')">空氣溫度</button>-->
+                        <!--</div>-->
+                    <!--</div>-->
+                    <!--<div class="col-xl-3 col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">-->
+                        <!--<div class="page-title text-center">-->
+                            <!--<button class="set-link" name="airHum" type="button" onclick="BurnProgram('airHum')">空氣濕度</button>-->
+                        <!--</div>-->
+                    <!--</div>-->
+                    <!--<div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">-->
+                        <!--<div class="page-title text-center">-->
+                            <!--<button class="set-link" name="dewPoint" type="button" onclick="BurnProgram('dewPoint')">露點</button>-->
+                        <!--</div>-->
+                    <!--</div>-->
+                    <!--<div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">-->
+                        <!--<div class="page-title text-center">-->
+                            <!--<button class="set-link" name="sun" type="button" onclick="BurnProgram('sun')">日照</button>-->
+                        <!--</div>-->
+                    <!--</div>-->
+                    <!--<div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">-->
+                        <!--<div class="page-title text-center">-->
+                            <!--<button class="set-link" name="soilHum" type="button" onclick="BurnProgram('soilHum')">土壤含水率</button>-->
+                        <!--</div>-->
+                    <!--</div>-->
+                    <!--<div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">-->
+                        <!--<div class="page-title text-center">-->
+                            <!--<button class="set-link" name="soilTem" type="button" onclick="BurnProgram('soilTem')">土壤溫度</button>-->
+                        <!--</div>-->
+                    <!--</div>-->
+                    <!--<div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">-->
+                        <!--<div class="page-title text-center">-->
+                            <!--<button class="set-link" name="soilEC" type="button" onclick="BurnProgram('soilEC')">土壤EC值</button>-->
+                        <!--</div>-->
+                    <!--</div>-->
+                    <!--<div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">-->
+                        <!--<div class="page-title text-center">-->
+                            <!--<button class="set-link" name="windSpd" type="button" onclick="BurnProgram('windSpd')">風速</button>-->
+                        <!--</div>-->
+                    <!--</div>-->
+                    <!--<div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">-->
+                        <!--<div class="page-title text-center">-->
+                            <!--<button class="set-link" name="windDin" type="button" onclick="BurnProgram('windDin')">風向</button>-->
+                        <!--</div>-->
+                    <!--</div>-->
+                    <!--<div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">-->
+                        <!--<div class="page-title text-center">-->
+                            <!--<button class="set-link" name="rain" type="button" onclick="BurnProgram('rain')">降雨量</button>-->
+                        <!--</div>-->
+                    <!--</div>-->
+                    <!--<div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">-->
+                        <!--<div class="page-title text-center">-->
+                            <!--<button class="set-link" name="atmosphere" type="button" onclick="BurnProgram('atmosphere')">大氣壓</button>-->
+                        <!--</div>-->
+                    <!--</div>-->
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>

+ 247 - 0
BBend-Test-JWT/app/templates/incoming_check.html

@@ -0,0 +1,247 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Aisky-Sixth</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+
+    <!-- 新 Bootstrap4 核心 CSS 文件 -->
+    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.1.0/css/bootstrap.min.css">
+
+    <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
+    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
+
+    <!-- popper.min.js 用于弹窗、提示、下拉菜单 -->
+    <script src="https://cdn.bootcss.com/popper.js/1.12.5/umd/popper.min.js"></script>
+
+    <!-- 最新的 Bootstrap4 核心 JavaScript 文件 -->
+    <script src="https://cdn.bootcss.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
+
+    <!--可用來建立使用者小圖示-->
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
+
+
+
+    <style>
+        body {
+	        margin:0;
+        }
+
+        .navbar-dark .navbar-nav .nav-link {
+            color: white;
+            cursor: pointer;
+	        text-decoration:none;
+            width: 130px;
+            height: 46px;
+        }
+
+        .nav-top {
+	        line-height:40px;
+	        background-color: #C4C4C4;
+        }
+
+        .website_title{
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: normal;
+            font-size: 30px;
+            color: #000000;
+        }
+
+        .navbar-nav > li{
+	        float: none;
+	        display: inline-block;
+	        width: 110px;
+            margin: 0 auto;
+            text-align: center;
+        }
+
+        .navbar-nav > li a{
+            font-size: 20px;
+        }
+
+        .main-page {
+            margin-top: 150px;
+        }
+
+        .page-title {
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: bold;
+            font-size: 36px;
+        }
+
+
+        .flex {
+            display: flex;
+            flex-direction: row;
+            flex-wrap: wrap;
+            justify-content: center;
+        }
+
+          .set-link {
+            display: inline-block;
+            width: 350px;
+            height: 100px;
+            line-height: 100px;
+            background: #008CBA;
+            border: 1px solid #CFCFCF;
+            box-sizing: border-box;
+            color: #FFFFFF;
+            border-radius: 10px;
+            font-size: 36px;
+
+        }
+
+        .fa{
+            display: inline-block;
+            font: normal normal normal 14px/1 FontAwesome;
+            font-size: inherit;
+            text-rendering: auto;
+            -webkit-font-smoothing: antialiased;
+        }
+
+        .fa-user-o:before{
+            content: "\f2c0";
+        }
+
+        button {
+            cursor: pointer;
+        }
+
+
+        @media(max-width:373px){
+            .card {
+                margin-right: 0px;
+            }
+        }
+
+        @media(max-width:577px){
+
+        }
+
+        @media(min-width:576px){
+
+
+        }
+         @media(min-width:768px){
+            .navbar-nav > li {
+                 margin-left: 0px;
+            }
+            .navbar-nav .li-block {
+                display:none;
+            }
+         }
+
+         @media(min-width:991px){
+            .navbar-nav > li {
+                 margin-left: 20px;
+            }
+            .navbar-nav .li-block {
+                display:none;
+            }
+         }
+
+         @media(min-width:1200px){
+            .navbar-nav > li {
+                 margin-left: 35px;
+            }
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 100px;
+            }
+         }
+
+         @media(min-width:1400px){
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 200px;
+            }
+
+         }
+
+
+         @media(min-width:1689px) {
+            .navbar-nav > li {
+                 margin-left: 50px;
+            }
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 500px;
+            }
+         }
+
+
+    </style>
+
+
+		<script>
+		    //驗證token,如果不符合或過期就登出回登入頁
+            var str = localStorage.getItem('Hello');
+            $.ajax({
+                type: "GET",
+                url: "/auth",
+                headers: {'Authorization': 'Bearer ' + str},
+                success: function(result){
+                    console.log(result.identity);
+                },
+                error: function(result){
+                    window.location.href='/logout';
+                }
+            });
+
+        </script>
+</head>
+<body>
+    <nav class="fixed-top">
+        <nav class="navbar navbar-expand-md nav-top justify-content-center">
+            <div>
+                <span class="website_title">進貨檢測</span>
+            </div>
+        </nav>
+        <nav class="navbar navbar-expand-md bg-dark navbar-dark nav-bottom">
+            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
+                <span class="navbar-toggler-icon"></span>
+            </button>
+            <div class="collapse navbar-collapse" id="collapsibleNavbar">
+                <ul class="navbar-nav">
+                    <li class="nav-item">
+                        <a class="nav-link" href="/">首頁</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/incoming_check">進貨檢測</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/burn_program">感測器燒錄</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/modify_permissions">權限設置</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/add_sensor">新增感測器</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/add_server">伺服器建置</a>
+                    </li>
+                    <li class="li-block"></li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="#"><i class="fa fa-user-o"></i> {{params.username}}</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/logout">Logout</a>
+                    </li>
+                </ul>
+            </div>
+        </nav>
+    </nav>
+    <div class="main-page">
+        <div class="container-fluid">
+            <div class="row">
+                <div class="col flex" style="margin: auto; ">
+
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>

+ 274 - 0
BBend-Test-JWT/app/templates/index.html

@@ -0,0 +1,274 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Aisky-Sixth</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+
+    <!-- 新 Bootstrap4 核心 CSS 文件 -->
+    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.1.0/css/bootstrap.min.css">
+
+    <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
+    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
+
+    <!-- popper.min.js 用于弹窗、提示、下拉菜单 -->
+    <script src="https://cdn.bootcss.com/popper.js/1.12.5/umd/popper.min.js"></script>
+
+    <!-- 最新的 Bootstrap4 核心 JavaScript 文件 -->
+    <script src="https://cdn.bootcss.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
+
+    <!--可用來建立使用者小圖示-->
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
+
+
+
+    <style>
+        body {
+	        margin:0;
+        }
+
+        .navbar-dark .navbar-nav .nav-link {
+            color: white;
+            cursor: pointer;
+	        text-decoration:none;
+            width: 130px;
+            height: 46px;
+        }
+
+        .nav-top {
+	        line-height:40px;
+	        background-color: #C4C4C4;
+        }
+
+        .website_title{
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: normal;
+            font-size: 30px;
+            color: #000000;
+        }
+
+        .navbar-nav > li{
+	        float: none;
+	        display: inline-block;
+	        width: 110px;
+            margin: 0 auto;
+            text-align: center;
+        }
+
+        .navbar-nav > li a{
+            font-size: 20px;
+        }
+
+        .main-page {
+            margin-top: 150px;
+        }
+
+        .page-title {
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: bold;
+            font-size: 36px;
+        }
+
+
+        .flex {
+            display: flex;
+            flex-direction: row;
+            flex-wrap: wrap;
+            justify-content: center;
+        }
+
+          .set-link {
+            display: inline-block;
+            width: 350px;
+            height: 100px;
+            line-height: 100px;
+            background: #008CBA;
+            border: 1px solid #CFCFCF;
+            box-sizing: border-box;
+            color: #FFFFFF;
+            border-radius: 10px;
+            font-size: 36px;
+
+        }
+
+        .fa{
+            display: inline-block;
+            font: normal normal normal 14px/1 FontAwesome;
+            font-size: inherit;
+            text-rendering: auto;
+            -webkit-font-smoothing: antialiased;
+        }
+
+        .fa-user-o:before{
+            content: "\f2c0";
+        }
+
+
+        @media(max-width:373px){
+            .card {
+                margin-right: 0px;
+            }
+        }
+
+        @media(max-width:577px){
+
+        }
+
+        @media(min-width:576px){
+
+
+        }
+         @media(min-width:768px){
+            .navbar-nav > li {
+                 margin-left: 0px;
+            }
+            .navbar-nav .li-block {
+                display:none;
+            }
+         }
+
+         @media(min-width:991px){
+            .navbar-nav > li {
+                 margin-left: 20px;
+            }
+            .navbar-nav .li-block {
+                display:none;
+            }
+         }
+
+         @media(min-width:1200px){
+            .navbar-nav > li {
+                 margin-left: 35px;
+            }
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 100px;
+            }
+         }
+
+         @media(min-width:1400px){
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 200px;
+            }
+
+         }
+
+
+         @media(min-width:1689px) {
+            .navbar-nav > li {
+                 margin-left: 50px;
+            }
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 500px;
+            }
+         }
+
+
+    </style>
+
+
+		<script>
+<!--            //驗證token,如果不符合或過期就登出回登入頁-->
+<!--            var str = localStorage.getItem('Hello');-->
+<!--            $.ajax({-->
+<!--                type: "GET",-->
+<!--                url: "/auth",-->
+<!--                headers: {'Authorization': 'Bearer ' + str},-->
+<!--                success: function(result){-->
+<!--                    console.log(result.identity);-->
+<!--                },-->
+<!--                error: function(result){-->
+<!--                    window.location.href='/logout';-->
+<!--                }-->
+<!--            });-->
+        </script>
+</head>
+<body>
+    <nav class="fixed-top">
+        <nav class="navbar navbar-expand-md nav-top justify-content-center">
+            <div>
+                <span class="website_title">首頁</span>
+            </div>
+        </nav>
+        <nav class="navbar navbar-expand-md bg-dark navbar-dark nav-bottom">
+            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
+                <span class="navbar-toggler-icon"></span>
+            </button>
+            <div class="collapse navbar-collapse" id="collapsibleNavbar">
+                <ul class="navbar-nav">
+                    <li class="nav-item">
+                        <a class="nav-link" href="/">首頁</a>
+                    </li>
+                    <li class="nav-item">
+                        <!--<a class="nav-link" href="/incoming_check" onclick="IncomingCheck();">進貨檢測</a>-->
+                        <a class="nav-link" href="/incoming_check">進貨檢測</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/burn_program">感測器燒錄</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/modify_permissions">權限設置</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/add_sensor">新增感測器</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/add_server">伺服器建置</a>
+                    </li>
+                    <li class="li-block"></li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="#"><i class="fa fa-user-o"></i> {{params.username}}</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/logout">Logout</a>
+                    </li>
+                </ul>
+            </div>
+        </nav>
+    </nav>
+    <div class="main-page">
+        <form method="" action="">
+            <div class="container-fluid">
+                <div class="row">
+                    <div class="col flex" style="margin: auto; ">
+                        <div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">
+                            <div class="page-title text-center">
+                                <a class="set-link" type="button" href="/">首頁</a>
+                            </div>
+                        </div>
+                        <div class="col-xl-3 col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">
+                            <div class="page-title text-center">
+                                <a class="set-link" type="button" href="/incoming_check">進貨檢測</a>
+                            </div>
+                        </div>
+                        <div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">
+                            <div class="page-title text-center">
+                                <a class="set-link" type="button" href="/burn_program">感測器燒錄</a>
+                            </div>
+                        </div>
+                        <div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">
+                            <div class="page-title text-center">
+                                <a class="set-link" type="button" href="/modify_permissions">權限設置</a>
+                            </div>
+                        </div>
+                        <div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">
+                            <div class="page-title text-center">
+                                <a class="set-link" type="button" href="/add_sensor">新增感測器</a>
+                            </div>
+                        </div>
+                        <div class="col-xl-3  col-lg-4 col-md-5 col-sm-8 col-xs-8" style="margin-right: 20px ;margin-left: 20px; margin-top:50px; margin-bottom:50px;">
+                            <div class="page-title text-center">
+                                <a class="set-link" type="button" href="/add_server">伺服器建置</a>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+</body>
+</html>

+ 246 - 0
BBend-Test-JWT/app/templates/modify_permissions.html

@@ -0,0 +1,246 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Aisky-Sixth</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+
+    <!-- 新 Bootstrap4 核心 CSS 文件 -->
+    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.1.0/css/bootstrap.min.css">
+
+    <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
+    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
+
+    <!-- popper.min.js 用于弹窗、提示、下拉菜单 -->
+    <script src="https://cdn.bootcss.com/popper.js/1.12.5/umd/popper.min.js"></script>
+
+    <!-- 最新的 Bootstrap4 核心 JavaScript 文件 -->
+    <script src="https://cdn.bootcss.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
+
+    <!--可用來建立使用者小圖示-->
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
+
+
+
+    <style>
+        body {
+	        margin:0;
+        }
+
+        .navbar-dark .navbar-nav .nav-link {
+            color: white;
+            cursor: pointer;
+	        text-decoration:none;
+            width: 130px;
+            height: 46px;
+        }
+
+        .nav-top {
+	        line-height:40px;
+	        background-color: #C4C4C4;
+        }
+
+        .website_title{
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: normal;
+            font-size: 30px;
+            color: #000000;
+        }
+
+        .navbar-nav > li{
+	        float: none;
+	        display: inline-block;
+	        width: 110px;
+            margin: 0 auto;
+            text-align: center;
+        }
+
+        .navbar-nav > li a{
+            font-size: 20px;
+        }
+
+        .main-page {
+            margin-top: 150px;
+        }
+
+        .page-title {
+            font-family: Roboto;
+            font-style: normal;
+            font-weight: bold;
+            font-size: 36px;
+        }
+
+
+        .flex {
+            display: flex;
+            flex-direction: row;
+            flex-wrap: wrap;
+            justify-content: center;
+        }
+
+          .set-link {
+            display: inline-block;
+            width: 350px;
+            height: 100px;
+            line-height: 100px;
+            background: #008CBA;
+            border: 1px solid #CFCFCF;
+            box-sizing: border-box;
+            color: #FFFFFF;
+            border-radius: 10px;
+            font-size: 36px;
+
+        }
+
+        .fa{
+            display: inline-block;
+            font: normal normal normal 14px/1 FontAwesome;
+            font-size: inherit;
+            text-rendering: auto;
+            -webkit-font-smoothing: antialiased;
+        }
+
+        .fa-user-o:before{
+            content: "\f2c0";
+        }
+
+        button {
+            cursor: pointer;
+        }
+
+
+        @media(max-width:373px){
+            .card {
+                margin-right: 0px;
+            }
+        }
+
+        @media(max-width:577px){
+
+        }
+
+        @media(min-width:576px){
+
+
+        }
+         @media(min-width:768px){
+            .navbar-nav > li {
+                 margin-left: 0px;
+            }
+            .navbar-nav .li-block {
+                display:none;
+            }
+         }
+
+         @media(min-width:991px){
+            .navbar-nav > li {
+                 margin-left: 20px;
+            }
+            .navbar-nav .li-block {
+                display:none;
+            }
+         }
+
+         @media(min-width:1200px){
+            .navbar-nav > li {
+                 margin-left: 35px;
+            }
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 100px;
+            }
+         }
+
+         @media(min-width:1400px){
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 200px;
+            }
+
+         }
+
+
+         @media(min-width:1689px) {
+            .navbar-nav > li {
+                 margin-left: 50px;
+            }
+            .navbar-nav .li-block {
+                display: inline-block;
+                width: 500px;
+            }
+         }
+
+
+    </style>
+
+		<script>
+            //驗證token,如果不符合或過期就登出回登入頁
+            var str = localStorage.getItem('Hello');
+            $.ajax({
+                type: "GET",
+                url: "/auth",
+                headers: {'Authorization': 'Bearer ' + str},
+                success: function(result){
+                    console.log(result.identity);
+                },
+                error: function(result){
+                    window.location.href='/logout';
+                }
+            });
+
+        </script>
+</head>
+<body>
+    <nav class="fixed-top">
+        <nav class="navbar navbar-expand-md nav-top justify-content-center">
+            <div>
+                <span class="website_title">權限設置</span>
+            </div>
+        </nav>
+        <nav class="navbar navbar-expand-md bg-dark navbar-dark nav-bottom">
+            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
+                <span class="navbar-toggler-icon"></span>
+            </button>
+            <div class="collapse navbar-collapse" id="collapsibleNavbar">
+                <ul class="navbar-nav">
+                    <li class="nav-item">
+                        <a class="nav-link" href="/">首頁</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/incoming_check">進貨檢測</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/burn_program">感測器燒錄</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/modify_permissions">權限設置</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/add_sensor">新增感測器</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/add_server">伺服器建置</a>
+                    </li>
+                    <li class="li-block"></li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="#"><i class="fa fa-user-o"></i> {{params.username}}</a>
+                    </li>
+                    <li class="nav-item">
+                        <a class="nav-link" href="/logout">Logout</a>
+                    </li>
+                </ul>
+            </div>
+        </nav>
+    </nav>
+    <div class="main-page">
+        <div class="container-fluid">
+            <div class="row">
+                <div class="col flex" style="margin: auto; ">
+
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>

+ 108 - 0
BBend-Test-JWT/app/templates/registration.html

@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Aisky-CowdungCart</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+
+    <!-- 新 Bootstrap4 核心 CSS 文件 -->
+    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.1.0/css/bootstrap.min.css">
+
+    <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
+    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
+
+    <!-- popper.min.js 用于弹窗、提示、下拉菜单 -->
+    <script src="https://cdn.bootcss.com/popper.js/1.12.5/umd/popper.min.js"></script>
+
+    <!-- 最新的 Bootstrap4 核心 JavaScript 文件 -->
+    <script src="https://cdn.bootcss.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
+
+    <script src="../static/js/registration.js"></script>
+
+    <link rel="stylesheet" href="../static/css/registration.css">
+
+    <script>
+            function Registration(){
+                var firstname = $("input[name='firstname']").val();
+                var lastname = $("input[name='lastname']").val();
+                var email = $("input[name='email']").val();
+                var phone = $("input[name='phone']").val();
+                var username = $("input[name='username']").val();
+                var password = $("input[name='password']").val();
+                var confirmpwd = $("input[name='confirmpwd']").val();
+                var data = {"firstname":firstname, "lastname":lastname, "email":email, "phone":phone, "username":username, "password":password};
+
+                $.ajax({
+                    url: "/login",
+                    type: "post",
+                    data: data,
+                    dataType: "json",
+                    success: function(res){
+                        if(res.access_token){
+                            console.log("test");
+                            localStorage.setItem('Hello', res.access_token);
+                            window.location.href='/';
+                        };
+                    },
+                });
+            };
+        </script>
+
+
+</head>
+<body>
+    <div class="container">
+        <div class="row">
+            <div class="col-2"></div>
+            <div class="col">
+                <img src="../static/img/logo_new.png" class="img-fluid">
+                <h1 class="text-center">Registration</h1>
+                <!--<form method="post" action="/register">-->
+                    <div class="form">
+                        <div class="wrong-info"><span id="firstname-span"></span></div>
+                        <div class="form-inline">
+                            <label for="first">First Name</label>
+                            <input type="text" class="form-control" id="first" name="firstname">
+                        </div>
+                        <div class="wrong-info"><span id="lastname-span"></span></div>
+                        <div class="form-inline">
+                            <label for="last">Last Name</label>
+                            <input type="text" class="form-control" id="last" name="lastname">
+                        </div>
+                        <div class="wrong-info"><span id="email-span"></span></div>
+                        <div class="form-inline">
+                            <label for="email">Email</label>
+                            <input type="email" class="form-control" id="email" name="email">
+                        </div>
+                        <div class="wrong-info"><span id="phone-span"></span></div>
+                        <div class="form-inline">
+                            <label for="phone">Phone</label>
+                            <input type="number" class="form-control" id="phone" name="phone">
+                        </div>
+                        <div class="wrong-info"><span id="username-span"></span></div>
+                        <div class="form-inline">
+                            <label for="usr">User Name</label>
+                            <input type="text" class="form-control" id="usr" name="username">
+                        </div>
+                        <div class="wrong-info"><span id="password-span"></span></div>
+                        <div class="form-inline">
+                            <label for="pwd">Password</label>
+                            <input type="password" class="form-control" id="pwd" name="password">
+                        </div>
+                        <div class="wrong-info"><span></span></div>
+                        <div class="form-inline">
+                            <label for="cpwd">Confirm Password</label>
+                            <input type="password" class="form-control" id="cpwd" name="confirmpwd">
+                        </div>
+                    </div>
+                    <div class="text-center">
+                        <input type="submit" class="btn btn-info" value="Register" onclick="Registration()" style="margin-right:70px;">
+                        <input type="button"  class="btn btn-info" value="Cancel" onclick="Login()">
+                    </div>
+                <!--</form>-->
+            </div>
+            <div class="col-2"></div>
+        </div>
+    </div>
+</body>
+</html>

+ 60 - 0
BBend-Test-JWT/app/templates/reset_pwd1.html

@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Aisky-CowdungCart</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+
+    <!-- 新 Bootstrap4 核心 CSS 文件 -->
+    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.1.0/css/bootstrap.min.css">
+
+    <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
+    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
+
+    <!-- popper.min.js 用于弹窗、提示、下拉菜单 -->
+    <script src="https://cdn.bootcss.com/popper.js/1.12.5/umd/popper.min.js"></script>
+
+    <!-- 最新的 Bootstrap4 核心 JavaScript 文件 -->
+    <script src="https://cdn.bootcss.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
+
+    <script src="../static/js/reset_pwd1.js"></script>
+
+    <link rel="stylesheet" href="../static/css/reset_pwd1.css">
+
+
+    {% if errMsg %}
+        <script>
+            $(function(){
+                $(".wrong-span").text("{{errMsg}}");
+            });
+        </script>
+    {% endif %}
+
+</head>
+<body>
+    <div class="container">
+        <div class="row">
+            <div class="col-2"></div>
+            <div class="col">
+                <img src="../static/img/logo_new.png" class="img-fluid">
+                <h1 class="text-center">Reset password</h1>
+                <div class="descripe text-center">write your email address</div>
+                <form method="post" action="/reset_password">
+                    <div class="wrong-info"><span class="wrong-span"></span></div>
+                    <div class="form">
+                        <div class="form-inline">
+                            <label for="email">Email</label>
+                            <input type="text" class="form-control" id="email" name="email">
+                        </div>
+                    </div>
+                    <div>
+                        <input type="button" class="btn btn-info" value="Cancel" onclick="Login();">
+                        <input type="submit"  class="btn btn-info" value="Confirm">
+                    </div>
+                </form>
+            </div>
+            <div class="col-2"></div>
+        </div>
+    </div>
+</body>
+</html>

+ 66 - 0
BBend-Test-JWT/app/templates/reset_pwd2.html

@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Aisky-CowdungCart</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+
+    <!-- 新 Bootstrap4 核心 CSS 文件 -->
+    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.1.0/css/bootstrap.min.css">
+
+    <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
+    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
+
+    <!-- popper.min.js 用于弹窗、提示、下拉菜单 -->
+    <script src="https://cdn.bootcss.com/popper.js/1.12.5/umd/popper.min.js"></script>
+
+    <!-- 最新的 Bootstrap4 核心 JavaScript 文件 -->
+    <script src="https://cdn.bootcss.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
+
+    <script src="../static/js/reset_pwd2.js"></script>
+
+    <link rel="stylesheet" href="../static/css/reset_pwd2.css">
+
+
+
+    {% if errMsg %}
+        <script>
+            $(function(){
+                $(".wrong-span").text("{{errMsg}}");
+            });
+        </script>
+    {% endif %}
+
+
+</head>
+<body>
+    <div class="container">
+        <div class="row">
+            <div class="col-2"></div>
+            <div class="col">
+                <img src="../static/img/logo_new.png" class="img-fluid">
+                <h1 class="text-center">Reset password</h1>
+                <div class="descripe text-center">create a new password</div>
+                <form method="post" action="/reset_password">
+                    <div class="wrong-info"><span class="wrong-span"></span></div>
+                    <div class="form">
+                        <div class="form-inline">
+                            <label for="new-pwd">New password</label>
+                            <input type="password" class="form-control" id="new-pwd" name="new_pwd">
+                        </div>
+                        <div class="form-inline">
+                            <label for="confirm-pwd">Confirm password</label>
+                            <input type="password" class="form-control" id="confirm-pwd" name="confirm_pwd">
+                        </div>
+                    </div>
+                    <div>
+                        <input type="button" class="btn btn-info" value="Cancel" onclick="ResetPassword();">
+                        <input type="submit"  class="btn btn-info" value="Confirm">
+                    </div>
+                </form>
+            </div>
+            <div class="col-2"></div>
+        </div>
+    </div>
+</body>
+</html>

+ 92 - 0
BBend-Test-JWT/app/templates/sign_in.html

@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Aisky-Sixth</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+
+    <!-- 新 Bootstrap4 核心 CSS 文件 -->
+    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.1.0/css/bootstrap.min.css">
+
+    <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
+    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
+
+    <!-- popper.min.js 用于弹窗、提示、下拉菜单 -->
+    <script src="https://cdn.bootcss.com/popper.js/1.12.5/umd/popper.min.js"></script>
+
+    <!-- 最新的 Bootstrap4 核心 JavaScript 文件 -->
+    <script src="https://cdn.bootcss.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
+
+    <script src="../static/js/sign_in.js"></script>
+
+    <link rel="stylesheet" href="../static/css/sign_in.css">
+
+    {% if errMsg %}
+        <script>
+            $(function(){
+                $(".wrong-span").text("{{errMsg}}");
+            });
+        </script>
+    {% endif %}
+
+        <script>
+            function SignIn(){
+                var username = $("input[name=username]").val();
+                var password = $("input[name=password]").val();
+                var data = {"username":username, "password":password};
+
+                $.ajax({
+                    url: "/login",
+                    type: "post",
+                    data: data,
+                    dataType: "json",
+                    success: function(res){
+                        if(res.access_token){
+                            console.log("test");
+                            localStorage.setItem('Hello', res.access_token);
+                            window.location.href='/';
+                        };
+                        if(res.errMsg){
+                            $(".wrong-span").text("{{errMsg}}");
+                        };
+                    },
+                });
+            };
+        </script>
+
+
+</head>
+<body>
+    <div class="container">
+        <div class="row">
+            <div class="col-2"></div>
+            <div class="col">
+                <img src="../static/img/logo_new.png" class="img-fluid">
+                <h1 class="text-center">Sign in</h1>
+                <!--<form method="post" action="/login">-->
+                <div class="wrong-info"><span class="wrong-span"></span></div>
+                <div class="form">
+                    <div class="form-inline">
+                        <label for="usr">Login</label>
+                        <input type="text" class="form-control" id="usr" name="username">
+                    </div>
+                    <div class="form-inline">
+                        <label for="pwd">Password</label>
+                        <input type="password" class="form-control" id="pwd" name="password">
+                    </div>
+                    <div class="radio">
+                        <label><input type="checkbox" name="rem">  Remember me</label>
+                        <a href="#">Reset password</a>
+                    </div>
+                </div>
+                <div class="text-center">
+                    <input type="submit" class="btn btn-info" value="Log in" onclick="SignIn()" style="margin-right:100px;">
+                    <input type="button"  class="btn btn-info" value="Registration" onclick="Registration()">
+                </div>
+                <!--</form>-->
+            </div>
+            <div class="col-2"></div>
+        </div>
+    </div>
+</body>
+</html>

+ 38 - 0
BBend-Test-JWT/app/templates/test.html

@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Title</title>
+
+    <style>
+        html, body {
+            height: 100%;
+            width: 100%;
+            margin: 0;
+            padding: 0;
+        }
+
+        #map {
+            height: 100%;
+            width: 100%;
+        }
+    </style>
+
+
+</head>
+<body>
+    <div id="map"></div>
+</body>
+
+    <script>
+      var map;
+      function initMap() {
+        map = new google.maps.Map(document.getElementById('map'), {
+          center: {lat: 40.689104, lng: -74.044599},
+          zoom: 16
+        });
+      }
+    </script>
+    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCJ9w3VZc4WsOhZ2wDBJIbKVaePc1SMG3E&callback=initMap"
+    async defer></script>
+</html>

+ 6 - 0
BBend-Test-JWT/app/user/__init__.py

@@ -0,0 +1,6 @@
+#user目錄:針對用戶業務邏輯處理的目錄
+#針對用戶業務邏輯處理的初始化行為
+
+from flask import Blueprint
+user = Blueprint('user',__name__)
+from . import views

TEMPAT SAMPAH
BBend-Test-JWT/app/user/__pycache__/__init__.cpython-35.pyc


TEMPAT SAMPAH
BBend-Test-JWT/app/user/__pycache__/__init__.cpython-36.pyc


TEMPAT SAMPAH
BBend-Test-JWT/app/user/__pycache__/views.cpython-35.pyc


TEMPAT SAMPAH
BBend-Test-JWT/app/user/__pycache__/views.cpython-36.pyc


+ 6 - 0
BBend-Test-JWT/app/user/views.py

@@ -0,0 +1,6 @@
+#針對用戶業務邏輯處理的視圖和路由的定義
+from . import user
+
+@user.route('/user')
+def user_index():
+    return "這是user中的首頁"

+ 272 - 0
BBend-Test-JWT/manage.py

@@ -0,0 +1,272 @@
+#啟動和管理項目
+from app import create_app
+from flask import render_template, request, session
+import paramiko
+import git
+import shutil
+from time import sleep as sl
+from threading import Lock
+import threading
+from concurrent.futures import ThreadPoolExecutor
+import csv
+
+
+app, db, mqtt, socketio = create_app()
+thread = None
+thread_lock = Lock()
+
+@socketio.on('connect_event', namespace='/test_conn')
+def connected_msg(msg):
+    print("connect success")
+    print(msg)
+    socketio.emit('stdout', 'success', namespace='/test_conn')
+    print(socketio)
+
+D = {"item_name":0, "command":0}
+
+#建置伺服器的訪問路徑
+@app.route('/add_server', methods=['POST', 'GET'])
+def add_server_views():
+    username = session['uname']
+    L = []
+    if request.method == 'GET':
+        repo = git.Repo.init(path='.')
+        new_repo = git.Repo.clone_from(url='http://60.250.156.230:3000/benson/TestSSH.git', to_path='../new')
+        with open('/home/benson/Project/new/All_installv3.2.sh') as f:
+            # content = f.read().split('-Dividing line-')
+            # D['item_name'] = content[0].split('\n')[1:]
+            # D['command'] = content[1].split('\n')
+            D['command'] = f.read().split('\n')
+
+        with open('/home/benson/Project/new/Item.txt') as f:
+            D['item_name'] = f.read().split('\n')
+            for item in D['item_name']:
+                L.append('.'.join(item.split('.')[1:]))
+
+            #刪除非空資料夾
+            try:
+                shutil.rmtree('/home/benson/Project/new')
+            except OSError as e:
+                print(f"Error:{e.strerror}")
+
+        # for i in range(0, len(D['item_name'])):
+        #     item = D['item_name'][i].split('=')[-1].replace('"','')
+        #     L.append(item)
+        # L = L[:-1]
+
+        L2= []
+        for i in range(0, len(D['command'])):
+            if D['command'][i] == "'" or D['command'][i] == '' or "#" in D['command'][i] or D['command'][i] == ' ':
+                continue
+            L2.append(D['command'][i])
+        D['command'] = L2
+
+        print(D['item_name'])
+        print(D['command'])
+        # content = D['item_name'] + D['command']
+        # for i in content:
+        #     print(i)
+        return render_template('add_server.html', params=locals())
+    else:
+        item_install_fail = 0
+        d = request.form.to_dict()
+        ip = d['ip']
+        username = d['username']
+        password = d['password']
+        print(ip)
+        print(username)
+        print(password)
+        try:
+            # 建立一個sshclient物件
+            ssh = paramiko.SSHClient()
+            # 允許將信任的主機自動加入到host_allow 列表,此方法必須放在connect方法的前面
+            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+            # 指定本地的RSA私鑰檔案,如果建立金鑰對時設定的有密碼,password為設定的密碼,如無不用指定password引數
+            # pkey = paramiko.RSAKey.from_private_key_file('/home/super/.ssh/id_rsa', password='12345')
+            # pkey = paramiko.RSAKey.from_private_key_file('/home/ptop/topicjie/scripts/keys/id_rsa')
+            # 建立連線
+            # ssh.connect(hostname=ip,
+            #             port=22,
+            #             username='gs1801',
+            #             pkey=pkey)
+            # with open('/home/benson/test11.sh') as f:
+            #     content = f.read().split('\n')[0:-1]
+            # print(content)
+            # L = []
+            # for i in range(0, len(D['ssh_content'])):
+            #     if "#" in D['ssh_content'][i] or D['ssh_content'][i] == '' or D['ssh_content'][i] == ' ':
+            #         continue
+            #     L.append(D['ssh_content'][i])
+            # for i in L:
+            #     print(i)
+
+            ssh.connect(hostname=ip,
+                        port=22,
+                        username=username,
+                        password=password)
+            # 假如帳號密碼正確沒有被捕捉到異常,傳送訊息給前端
+            socketio.emit('user-confirm', 'pass', namespace='/test_conn')
+            # os.system("scp /home/benson/test10.sh gs1801@" + ip + ":/home/gs1801/")
+            # 執行命令
+            # stdin, stdout, stderr = ssh.exec_command("ls -l /home/gs1801;touch test7.py")
+            # stdin, stdout, stderr = ssh.exec_command("touch test10.sh;echo '" + content + "' >> test10.sh;bash test10.sh")
+            # print('test1')
+            # print(stdout.read().decode())
+            # print('test2')
+            # print(stderr.read().decode())
+
+            # content = D['item_name'] + D['command']
+            with open('ItemFile.csv', 'w', newline='') as csvFile:
+                csvWriter = csv.writer(csvFile)
+                csvWriter.writerow(['Command','Install Content','Status'])
+
+            for command in D['command']:
+                if '使用者' in command :
+                    command = command.replace('使用者', username)
+                print(command)
+                sl(6)
+                stdin, stdout, stderr = ssh.exec_command(command)
+                #
+                #     # print(stdout.read().decode())
+                #     # print('----------------------------------------')
+                #     # print(stderr.read().decode())
+                #
+                error = stderr.read().decode()
+                if error:
+                    print('error')
+                    print(error)
+                    if item_install_fail == 0:
+                        item_install_fail = 1
+                    with open('ItemFile.csv', 'a', newline='') as csvFile:
+                        csvWriter = csv.writer(csvFile)
+                        csvWriter.writerow([command, error, 'error'])
+
+                    socketio.emit('stderr', error, namespace='/test_conn')
+                else:
+                    print('success')
+                    success = stdout.read().decode()
+                    print(success)
+                    with open('ItemFile.csv', 'a', newline='') as csvFile:
+                        csvWriter = csv.writer(csvFile)
+                        csvWriter.writerow([command, success, 'success'])
+                    socketio.emit('stdout', success, namespace='/test_conn')
+
+                print('-----------------------------------------------------------------------------')
+
+
+            # def sshJob():
+            #     for command in content:
+            #         stdin, stdout, stderr = ssh.exec_command(command)
+            #     #
+            #     #     # print(stdout.read().decode())
+            #     #     # print('----------------------------------------')
+            #     #     # print(stderr.read().decode())
+            #     #
+            #         print(stdin)
+            #         if stderr.read().decode():
+            #             L.append(0)
+            #             print('error')
+            #             socketio.emit('stderr', stderr.read().decode())
+            #         else:
+            #             L.append(1)
+            #             print('success')
+            #             socketio.emit('stdout', stdout.read().decode())
+            #         sl(5)
+            #     ssh.close()
+
+            # def sshJob():
+            #     sl(5)
+            #     i = 0
+            #     total = len(content)
+            #     while True:
+            #         stdin, stdout, stderr = ssh.exec_command(content[i])
+            #     #
+            #     #     # print(stdout.read().decode())
+            #     #     # print('----------------------------------------')
+            #     #     # print(stderr.read().decode())
+            #     #
+            #         if stderr.read().decode():
+            #             L.append(0)
+            #             print('error')
+            #             socketio.emit('stderr', stderr.read().decode())
+            #         else:
+            #             L.append(1)
+            #             print('success')
+            #             socketio.emit('stdout', stdout.read().decode())
+            #         sl(5)
+            #         i += 1
+            #         if i == total:
+            #             break
+            #     ssh.close()
+
+            # ssh_thread = threading.Thread(target=sshJob)
+            # ssh_thread.daemon = True
+            # ssh_thread.start()
+
+            # global thread
+            # with thread_lock:
+            #     if thread is None:
+            #         thread = socketio.start_background_task(target=sshJob)
+
+            # print(L)
+            #
+            # item_list = ItemList()
+            # item_list.ip = ip
+            # item_list.pymysql = L[0]
+            # item_list.eventlet = L[1]
+            # datetime = dt.now()
+            # item_list.datetime = datetime
+            # db.session.add(item_list)
+            # db.session.commit()
+
+            # 關閉連線
+            ssh.close()
+            if item_install_fail:
+                res = '有套件未安裝完成!'
+            else:
+                res = '建置完成!'
+            return res
+        except Exception as e:
+            print(e)
+            return str(e)
+
+
+
+#mqtt發布
+@app.route('/mqtt', methods=['GET','POST'])
+def mqtt_views():
+    import json
+    dict = request.args.to_dict()
+    json = json.dumps(dict)
+    print(json)
+    mqtt.publish('AISKY/AppleFarm/MK-G/b8:27:eb:f8:24:92', json)
+    return "Publish done"
+
+
+#mqtt訂閱
+@mqtt.on_connect()
+def handle_connect(client, userdata, flags, rc):
+    mqtt.subscribe('AISKY/AppleFarm/MK-G/b8:27:eb:f8:24:92/Log')
+
+#處理mqtt訂閱的信息
+@mqtt.on_message()
+def handle_mqtt_message(client, userdata, message):
+    payload = message.payload.decode()
+    # p = json.loads(payload)
+    # print("-------msg-------")
+    # print('name  :', p['name'])
+    # print('email :', p['email'])
+    print(payload)
+
+#調用日誌訊息
+@mqtt.on_log()
+def handle_logging(client, userdata, level, buf):
+    print(level, buf)
+
+#自動關閉所有未使用、掛著的連接
+@app.teardown_appcontext
+def shutdown_session(exception=None):
+        db.session.remove()
+
+if __name__ == '__main__':
+    socketio.run(app, debug=True, host='0.0.0.0', port=5000)

+ 1 - 0
BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/INSTALLER

@@ -0,0 +1 @@
+pip

+ 28 - 0
BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/LICENSE.rst

@@ -0,0 +1,28 @@
+Copyright 2010 Pallets
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1.  Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+2.  Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+3.  Neither the name of the copyright holder nor the names of its
+    contributors may be used to endorse or promote products derived from
+    this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 137 - 0
BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/METADATA

@@ -0,0 +1,137 @@
+Metadata-Version: 2.1
+Name: Flask
+Version: 1.1.2
+Summary: A simple framework for building complex web applications.
+Home-page: https://palletsprojects.com/p/flask/
+Author: Armin Ronacher
+Author-email: armin.ronacher@active-4.com
+Maintainer: Pallets
+Maintainer-email: contact@palletsprojects.com
+License: BSD-3-Clause
+Project-URL: Documentation, https://flask.palletsprojects.com/
+Project-URL: Code, https://github.com/pallets/flask
+Project-URL: Issue tracker, https://github.com/pallets/flask/issues
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Framework :: Flask
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
+Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
+Requires-Dist: Werkzeug (>=0.15)
+Requires-Dist: Jinja2 (>=2.10.1)
+Requires-Dist: itsdangerous (>=0.24)
+Requires-Dist: click (>=5.1)
+Provides-Extra: dev
+Requires-Dist: pytest ; extra == 'dev'
+Requires-Dist: coverage ; extra == 'dev'
+Requires-Dist: tox ; extra == 'dev'
+Requires-Dist: sphinx ; extra == 'dev'
+Requires-Dist: pallets-sphinx-themes ; extra == 'dev'
+Requires-Dist: sphinxcontrib-log-cabinet ; extra == 'dev'
+Requires-Dist: sphinx-issues ; extra == 'dev'
+Provides-Extra: docs
+Requires-Dist: sphinx ; extra == 'docs'
+Requires-Dist: pallets-sphinx-themes ; extra == 'docs'
+Requires-Dist: sphinxcontrib-log-cabinet ; extra == 'docs'
+Requires-Dist: sphinx-issues ; extra == 'docs'
+Provides-Extra: dotenv
+Requires-Dist: python-dotenv ; extra == 'dotenv'
+
+Flask
+=====
+
+Flask is a lightweight `WSGI`_ web application framework. It is designed
+to make getting started quick and easy, with the ability to scale up to
+complex applications. It began as a simple wrapper around `Werkzeug`_
+and `Jinja`_ and has become one of the most popular Python web
+application frameworks.
+
+Flask offers suggestions, but doesn't enforce any dependencies or
+project layout. It is up to the developer to choose the tools and
+libraries they want to use. There are many extensions provided by the
+community that make adding new functionality easy.
+
+
+Installing
+----------
+
+Install and update using `pip`_:
+
+.. code-block:: text
+
+    pip install -U Flask
+
+
+A Simple Example
+----------------
+
+.. code-block:: python
+
+    from flask import Flask
+
+    app = Flask(__name__)
+
+    @app.route("/")
+    def hello():
+        return "Hello, World!"
+
+.. code-block:: text
+
+    $ env FLASK_APP=hello.py flask run
+     * Serving Flask app "hello"
+     * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
+
+
+Contributing
+------------
+
+For guidance on setting up a development environment and how to make a
+contribution to Flask, see the `contributing guidelines`_.
+
+.. _contributing guidelines: https://github.com/pallets/flask/blob/master/CONTRIBUTING.rst
+
+
+Donate
+------
+
+The Pallets organization develops and supports Flask and the libraries
+it uses. In order to grow the community of contributors and users, and
+allow the maintainers to devote more time to the projects, `please
+donate today`_.
+
+.. _please donate today: https://psfmember.org/civicrm/contribute/transact?reset=1&id=20
+
+
+Links
+-----
+
+* Website: https://palletsprojects.com/p/flask/
+* Documentation: https://flask.palletsprojects.com/
+* Releases: https://pypi.org/project/Flask/
+* Code: https://github.com/pallets/flask
+* Issue tracker: https://github.com/pallets/flask/issues
+* Test status: https://dev.azure.com/pallets/flask/_build
+* Official chat: https://discord.gg/t6rrQZH
+
+.. _WSGI: https://wsgi.readthedocs.io
+.. _Werkzeug: https://www.palletsprojects.com/p/werkzeug/
+.. _Jinja: https://www.palletsprojects.com/p/jinja/
+.. _pip: https://pip.pypa.io/en/stable/quickstart/
+
+

+ 49 - 0
BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/RECORD

@@ -0,0 +1,49 @@
+../../Scripts/flask.exe,sha256=wSacHuA_RDbtRmLUJXnQ4yyb9E2Sl_CRK2XEyxrG2U4,106356
+Flask-1.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+Flask-1.1.2.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475
+Flask-1.1.2.dist-info/METADATA,sha256=3INpPWH6nKfZ33R2N-bQZy4TOe1wQCMweZc9mwcNrtc,4591
+Flask-1.1.2.dist-info/RECORD,,
+Flask-1.1.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+Flask-1.1.2.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110
+Flask-1.1.2.dist-info/entry_points.txt,sha256=gBLA1aKg0OYR8AhbAfg8lnburHtKcgJLDU52BBctN0k,42
+Flask-1.1.2.dist-info/top_level.txt,sha256=dvi65F6AeGWVU0TBpYiC04yM60-FX1gJFkK31IKQr5c,6
+flask/__init__.py,sha256=YnA9wkwbJcnb_jTT-nMsMFeFE_UWt33khKzdHmMSuyI,1894
+flask/__main__.py,sha256=fjVtt3QTANXlpJCOv3Ha7d5H-76MwzSIOab7SFD9TEk,254
+flask/__pycache__/__init__.cpython-35.pyc,,
+flask/__pycache__/__main__.cpython-35.pyc,,
+flask/__pycache__/_compat.cpython-35.pyc,,
+flask/__pycache__/app.cpython-35.pyc,,
+flask/__pycache__/blueprints.cpython-35.pyc,,
+flask/__pycache__/cli.cpython-35.pyc,,
+flask/__pycache__/config.cpython-35.pyc,,
+flask/__pycache__/ctx.cpython-35.pyc,,
+flask/__pycache__/debughelpers.cpython-35.pyc,,
+flask/__pycache__/globals.cpython-35.pyc,,
+flask/__pycache__/helpers.cpython-35.pyc,,
+flask/__pycache__/logging.cpython-35.pyc,,
+flask/__pycache__/sessions.cpython-35.pyc,,
+flask/__pycache__/signals.cpython-35.pyc,,
+flask/__pycache__/templating.cpython-35.pyc,,
+flask/__pycache__/testing.cpython-35.pyc,,
+flask/__pycache__/views.cpython-35.pyc,,
+flask/__pycache__/wrappers.cpython-35.pyc,,
+flask/_compat.py,sha256=8KPT54Iig96TuLipdogLRHNYToIcg-xPhnSV5VRERnw,4099
+flask/app.py,sha256=tmEhx_XrIRP24vZg39dHMWFzJ2jj-YxIcd51LaIT5cE,98059
+flask/blueprints.py,sha256=vkdm8NusGsfZUeIfPdCluj733QFmiQcT4Sk1tuZLUjw,21400
+flask/cli.py,sha256=SIb22uq9wYBeB2tKMl0pYdhtZ1MAQyZtPL-3m6es4G0,31035
+flask/config.py,sha256=3dejvQRYfNHw_V7dCLMxU8UNFpL34xIKemN7gHZIZ8Y,10052
+flask/ctx.py,sha256=cks-omGedkxawHFo6bKIrdOHsJCAgg1i_NWw_htxb5U,16724
+flask/debughelpers.py,sha256=-whvPKuAoU8AZ9c1z_INuOeBgfYDqE1J2xNBsoriugU,6475
+flask/globals.py,sha256=OgcHb6_NCyX6-TldciOdKcyj4PNfyQwClxdMhvov6aA,1637
+flask/helpers.py,sha256=IHa578HU_3XAAo1wpXQv24MYRYO5TzaiDQQwvUIcE6Q,43074
+flask/json/__init__.py,sha256=6nITbZYiYOPB8Qfi1-dvsblwn01KRz8VOsMBIZyaYek,11988
+flask/json/__pycache__/__init__.cpython-35.pyc,,
+flask/json/__pycache__/tag.cpython-35.pyc,,
+flask/json/tag.py,sha256=vq9GOllg_0kTWKuVFrwmkeOQzR-jdBD23x-89JyCCQI,8306
+flask/logging.py,sha256=WcY5UkqTysGfmosyygSlXyZYGwOp3y-VsE6ehoJ48dk,3250
+flask/sessions.py,sha256=G0KsEkr_i1LG_wOINwFSOW3ts7Xbv4bNgEZKc7TRloc,14360
+flask/signals.py,sha256=yYLOed2x8WnQ7pirGalQYfpYpCILJ0LJhmNSrnWvjqw,2212
+flask/templating.py,sha256=F8E_IZXn9BGsjMzUJ5N_ACMyZdiFBp_SSEaUunvfZ7g,4939
+flask/testing.py,sha256=WXsciCQbHBP7xjHqNvOA4bT0k86GvSNpgzncfXLDEEg,10146
+flask/views.py,sha256=eeWnadLAj0QdQPLtjKipDetRZyG62CT2y7fNOFDJz0g,5802
+flask/wrappers.py,sha256=kgsvtZuMM6RQaDqhRbc5Pcj9vqTnaERl2pmXcdGL7LU,4736

+ 0 - 0
BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/REQUESTED


+ 6 - 0
BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/WHEEL

@@ -0,0 +1,6 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.33.6)
+Root-Is-Purelib: true
+Tag: py2-none-any
+Tag: py3-none-any
+

+ 3 - 0
BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/entry_points.txt

@@ -0,0 +1,3 @@
+[console_scripts]
+flask = flask.cli:main
+

+ 1 - 0
BBend-Test-JWT/venv/Lib/site-packages/Flask-1.1.2.dist-info/top_level.txt

@@ -0,0 +1 @@
+flask

+ 1 - 0
BBend-Test-JWT/venv/Lib/site-packages/Jinja2-2.11.2.dist-info/INSTALLER

@@ -0,0 +1 @@
+pip

+ 28 - 0
BBend-Test-JWT/venv/Lib/site-packages/Jinja2-2.11.2.dist-info/LICENSE.rst

@@ -0,0 +1,28 @@
+Copyright 2007 Pallets
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1.  Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+2.  Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+3.  Neither the name of the copyright holder nor the names of its
+    contributors may be used to endorse or promote products derived from
+    this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 106 - 0
BBend-Test-JWT/venv/Lib/site-packages/Jinja2-2.11.2.dist-info/METADATA

@@ -0,0 +1,106 @@
+Metadata-Version: 2.1
+Name: Jinja2
+Version: 2.11.2
+Summary: A very fast and expressive template engine.
+Home-page: https://palletsprojects.com/p/jinja/
+Author: Armin Ronacher
+Author-email: armin.ronacher@active-4.com
+Maintainer: Pallets
+Maintainer-email: contact@palletsprojects.com
+License: BSD-3-Clause
+Project-URL: Documentation, https://jinja.palletsprojects.com/
+Project-URL: Code, https://github.com/pallets/jinja
+Project-URL: Issue tracker, https://github.com/pallets/jinja/issues
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Text Processing :: Markup :: HTML
+Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
+Description-Content-Type: text/x-rst
+Requires-Dist: MarkupSafe (>=0.23)
+Provides-Extra: i18n
+Requires-Dist: Babel (>=0.8) ; extra == 'i18n'
+
+Jinja
+=====
+
+Jinja is a fast, expressive, extensible templating engine. Special
+placeholders in the template allow writing code similar to Python
+syntax. Then the template is passed data to render the final document.
+
+It includes:
+
+-   Template inheritance and inclusion.
+-   Define and import macros within templates.
+-   HTML templates can use autoescaping to prevent XSS from untrusted
+    user input.
+-   A sandboxed environment can safely render untrusted templates.
+-   AsyncIO support for generating templates and calling async
+    functions.
+-   I18N support with Babel.
+-   Templates are compiled to optimized Python code just-in-time and
+    cached, or can be compiled ahead-of-time.
+-   Exceptions point to the correct line in templates to make debugging
+    easier.
+-   Extensible filters, tests, functions, and even syntax.
+
+Jinja's philosophy is that while application logic belongs in Python if
+possible, it shouldn't make the template designer's job difficult by
+restricting functionality too much.
+
+
+Installing
+----------
+
+Install and update using `pip`_:
+
+.. code-block:: text
+
+    $ pip install -U Jinja2
+
+.. _pip: https://pip.pypa.io/en/stable/quickstart/
+
+
+In A Nutshell
+-------------
+
+.. code-block:: jinja
+
+    {% extends "base.html" %}
+    {% block title %}Members{% endblock %}
+    {% block content %}
+      <ul>
+      {% for user in users %}
+        <li><a href="{{ user.url }}">{{ user.username }}</a></li>
+      {% endfor %}
+      </ul>
+    {% endblock %}
+
+
+Links
+-----
+
+-   Website: https://palletsprojects.com/p/jinja/
+-   Documentation: https://jinja.palletsprojects.com/
+-   Releases: https://pypi.org/project/Jinja2/
+-   Code: https://github.com/pallets/jinja
+-   Issue tracker: https://github.com/pallets/jinja/issues
+-   Test status: https://dev.azure.com/pallets/jinja/_build
+-   Official chat: https://discord.gg/t6rrQZH
+
+

+ 59 - 0
BBend-Test-JWT/venv/Lib/site-packages/Jinja2-2.11.2.dist-info/RECORD

@@ -0,0 +1,59 @@
+Jinja2-2.11.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+Jinja2-2.11.2.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475
+Jinja2-2.11.2.dist-info/METADATA,sha256=5ZHRZoIRAMHsJPnqhlJ622_dRPsYePYJ-9EH4-Ry7yI,3535
+Jinja2-2.11.2.dist-info/RECORD,,
+Jinja2-2.11.2.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110
+Jinja2-2.11.2.dist-info/entry_points.txt,sha256=Qy_DkVo6Xj_zzOtmErrATe8lHZhOqdjpt3e4JJAGyi8,61
+Jinja2-2.11.2.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7
+jinja2/__init__.py,sha256=0QCM_jKKDM10yzSdHRVV4mQbCbDqf0GN0GirAqibn9Y,1549
+jinja2/__pycache__/__init__.cpython-35.pyc,,
+jinja2/__pycache__/_compat.cpython-35.pyc,,
+jinja2/__pycache__/_identifier.cpython-35.pyc,,
+jinja2/__pycache__/bccache.cpython-35.pyc,,
+jinja2/__pycache__/compiler.cpython-35.pyc,,
+jinja2/__pycache__/constants.cpython-35.pyc,,
+jinja2/__pycache__/debug.cpython-35.pyc,,
+jinja2/__pycache__/defaults.cpython-35.pyc,,
+jinja2/__pycache__/environment.cpython-35.pyc,,
+jinja2/__pycache__/exceptions.cpython-35.pyc,,
+jinja2/__pycache__/ext.cpython-35.pyc,,
+jinja2/__pycache__/filters.cpython-35.pyc,,
+jinja2/__pycache__/idtracking.cpython-35.pyc,,
+jinja2/__pycache__/lexer.cpython-35.pyc,,
+jinja2/__pycache__/loaders.cpython-35.pyc,,
+jinja2/__pycache__/meta.cpython-35.pyc,,
+jinja2/__pycache__/nativetypes.cpython-35.pyc,,
+jinja2/__pycache__/nodes.cpython-35.pyc,,
+jinja2/__pycache__/optimizer.cpython-35.pyc,,
+jinja2/__pycache__/parser.cpython-35.pyc,,
+jinja2/__pycache__/runtime.cpython-35.pyc,,
+jinja2/__pycache__/sandbox.cpython-35.pyc,,
+jinja2/__pycache__/tests.cpython-35.pyc,,
+jinja2/__pycache__/utils.cpython-35.pyc,,
+jinja2/__pycache__/visitor.cpython-35.pyc,,
+jinja2/_compat.py,sha256=B6Se8HjnXVpzz9-vfHejn-DV2NjaVK-Iewupc5kKlu8,3191
+jinja2/_identifier.py,sha256=EdgGJKi7O1yvr4yFlvqPNEqV6M1qHyQr8Gt8GmVTKVM,1775
+jinja2/asyncfilters.py,sha256=XJtYXTxFvcJ5xwk6SaDL4S0oNnT0wPYvXBCSzc482fI,4250
+jinja2/asyncsupport.py,sha256=ZBFsDLuq3Gtji3Ia87lcyuDbqaHZJRdtShZcqwpFnSQ,7209
+jinja2/bccache.py,sha256=3Pmp4jo65M9FQuIxdxoDBbEDFwe4acDMQf77nEJfrHA,12139
+jinja2/compiler.py,sha256=Ta9W1Lit542wItAHXlDcg0sEOsFDMirCdlFPHAurg4o,66284
+jinja2/constants.py,sha256=RR1sTzNzUmKco6aZicw4JpQpJGCuPuqm1h1YmCNUEFY,1458
+jinja2/debug.py,sha256=neR7GIGGjZH3_ILJGVUYy3eLQCCaWJMXOb7o0kGInWc,8529
+jinja2/defaults.py,sha256=85B6YUUCyWPSdrSeVhcqFVuu_bHUAQXeey--FIwSeVQ,1126
+jinja2/environment.py,sha256=XDSLKc4SqNLMOwTSq3TbWEyA5WyXfuLuVD0wAVjEFwM,50629
+jinja2/exceptions.py,sha256=VjNLawcmf2ODffqVMCQK1cRmvFaUfQWF4u8ouP3QPcE,5425
+jinja2/ext.py,sha256=AtwL5O5enT_L3HR9-oBvhGyUTdGoyaqG_ICtnR_EVd4,26441
+jinja2/filters.py,sha256=_RpPgAlgIj7ExvyDzcHAC3B36cocfWK-1TEketbNeM0,41415
+jinja2/idtracking.py,sha256=J3O4VHsrbf3wzwiBc7Cro26kHb6_5kbULeIOzocchIU,9211
+jinja2/lexer.py,sha256=nUFLRKhhKmmEWkLI65nQePgcQs7qsRdjVYZETMt_v0g,30331
+jinja2/loaders.py,sha256=C-fST_dmFjgWkp0ZuCkrgICAoOsoSIF28wfAFink0oU,17666
+jinja2/meta.py,sha256=QjyYhfNRD3QCXjBJpiPl9KgkEkGXJbAkCUq4-Ur10EQ,4131
+jinja2/nativetypes.py,sha256=Ul__gtVw4xH-0qvUvnCNHedQeNDwmEuyLJztzzSPeRg,2753
+jinja2/nodes.py,sha256=Mk1oJPVgIjnQw9WOqILvcu3rLepcFZ0ahxQm2mbwDwc,31095
+jinja2/optimizer.py,sha256=gQLlMYzvQhluhzmAIFA1tXS0cwgWYOjprN-gTRcHVsc,1457
+jinja2/parser.py,sha256=fcfdqePNTNyvosIvczbytVA332qpsURvYnCGcjDHSkA,35660
+jinja2/runtime.py,sha256=0y-BRyIEZ9ltByL2Id6GpHe1oDRQAwNeQvI0SKobNMw,30618
+jinja2/sandbox.py,sha256=knayyUvXsZ-F0mk15mO2-ehK9gsw04UhB8td-iUOtLc,17127
+jinja2/tests.py,sha256=iO_Y-9Vo60zrVe1lMpSl5sKHqAxe2leZHC08OoZ8K24,4799
+jinja2/utils.py,sha256=OoVMlQe9S2-lWT6jJbTu9tDuDvGNyWUhHDcE51i5_Do,22522
+jinja2/visitor.py,sha256=DUHupl0a4PGp7nxRtZFttUzAi1ccxzqc2hzetPYUz8U,3240

+ 6 - 0
BBend-Test-JWT/venv/Lib/site-packages/Jinja2-2.11.2.dist-info/WHEEL

@@ -0,0 +1,6 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.34.2)
+Root-Is-Purelib: true
+Tag: py2-none-any
+Tag: py3-none-any
+

+ 3 - 0
BBend-Test-JWT/venv/Lib/site-packages/Jinja2-2.11.2.dist-info/entry_points.txt

@@ -0,0 +1,3 @@
+[babel.extractors]
+jinja2 = jinja2.ext:babel_extract [i18n]
+

+ 1 - 0
BBend-Test-JWT/venv/Lib/site-packages/Jinja2-2.11.2.dist-info/top_level.txt

@@ -0,0 +1 @@
+jinja2

+ 1 - 0
BBend-Test-JWT/venv/Lib/site-packages/MarkupSafe-1.1.1.dist-info/INSTALLER

@@ -0,0 +1 @@
+pip

+ 28 - 0
BBend-Test-JWT/venv/Lib/site-packages/MarkupSafe-1.1.1.dist-info/LICENSE.rst

@@ -0,0 +1,28 @@
+Copyright 2010 Pallets
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1.  Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+2.  Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+3.  Neither the name of the copyright holder nor the names of its
+    contributors may be used to endorse or promote products derived from
+    this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 103 - 0
BBend-Test-JWT/venv/Lib/site-packages/MarkupSafe-1.1.1.dist-info/METADATA

@@ -0,0 +1,103 @@
+Metadata-Version: 2.1
+Name: MarkupSafe
+Version: 1.1.1
+Summary: Safely add untrusted strings to HTML/XML markup.
+Home-page: https://palletsprojects.com/p/markupsafe/
+Author: Armin Ronacher
+Author-email: armin.ronacher@active-4.com
+Maintainer: The Pallets Team
+Maintainer-email: contact@palletsprojects.com
+License: BSD-3-Clause
+Project-URL: Documentation, https://markupsafe.palletsprojects.com/
+Project-URL: Code, https://github.com/pallets/markupsafe
+Project-URL: Issue tracker, https://github.com/pallets/markupsafe/issues
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Topic :: Text Processing :: Markup :: HTML
+Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*
+
+MarkupSafe
+==========
+
+MarkupSafe implements a text object that escapes characters so it is
+safe to use in HTML and XML. Characters that have special meanings are
+replaced so that they display as the actual characters. This mitigates
+injection attacks, meaning untrusted user input can safely be displayed
+on a page.
+
+
+Installing
+----------
+
+Install and update using `pip`_:
+
+.. code-block:: text
+
+    pip install -U MarkupSafe
+
+.. _pip: https://pip.pypa.io/en/stable/quickstart/
+
+
+Examples
+--------
+
+.. code-block:: pycon
+
+    >>> from markupsafe import Markup, escape
+    >>> # escape replaces special characters and wraps in Markup
+    >>> escape('<script>alert(document.cookie);</script>')
+    Markup(u'&lt;script&gt;alert(document.cookie);&lt;/script&gt;')
+    >>> # wrap in Markup to mark text "safe" and prevent escaping
+    >>> Markup('<strong>Hello</strong>')
+    Markup('<strong>hello</strong>')
+    >>> escape(Markup('<strong>Hello</strong>'))
+    Markup('<strong>hello</strong>')
+    >>> # Markup is a text subclass (str on Python 3, unicode on Python 2)
+    >>> # methods and operators escape their arguments
+    >>> template = Markup("Hello <em>%s</em>")
+    >>> template % '"World"'
+    Markup('Hello <em>&#34;World&#34;</em>')
+
+
+Donate
+------
+
+The Pallets organization develops and supports MarkupSafe and other
+libraries that use it. In order to grow the community of contributors
+and users, and allow the maintainers to devote more time to the
+projects, `please donate today`_.
+
+.. _please donate today: https://palletsprojects.com/donate
+
+
+Links
+-----
+
+*   Website: https://palletsprojects.com/p/markupsafe/
+*   Documentation: https://markupsafe.palletsprojects.com/
+*   License: `BSD-3-Clause <https://github.com/pallets/markupsafe/blob/master/LICENSE.rst>`_
+*   Releases: https://pypi.org/project/MarkupSafe/
+*   Code: https://github.com/pallets/markupsafe
+*   Issue tracker: https://github.com/pallets/markupsafe/issues
+*   Test status:
+
+    *   Linux, Mac: https://travis-ci.org/pallets/markupsafe
+    *   Windows: https://ci.appveyor.com/project/pallets/markupsafe
+
+*   Test coverage: https://codecov.io/gh/pallets/markupsafe
+
+

+ 15 - 0
BBend-Test-JWT/venv/Lib/site-packages/MarkupSafe-1.1.1.dist-info/RECORD

@@ -0,0 +1,15 @@
+MarkupSafe-1.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+MarkupSafe-1.1.1.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475
+MarkupSafe-1.1.1.dist-info/METADATA,sha256=nJHwJ4_4ka-V39QH883jPrslj6inNdyyNASBXbYgHXQ,3570
+MarkupSafe-1.1.1.dist-info/RECORD,,
+MarkupSafe-1.1.1.dist-info/WHEEL,sha256=Q_8UIgV2becTkGqdKVgmaXdyabd83UTktF08jttIiu0,106
+MarkupSafe-1.1.1.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11
+markupsafe/__init__.py,sha256=oTblO5f9KFM-pvnq9bB0HgElnqkJyqHnFN1Nx2NIvnY,10126
+markupsafe/__pycache__/__init__.cpython-35.pyc,,
+markupsafe/__pycache__/_compat.cpython-35.pyc,,
+markupsafe/__pycache__/_constants.cpython-35.pyc,,
+markupsafe/__pycache__/_native.cpython-35.pyc,,
+markupsafe/_compat.py,sha256=uEW1ybxEjfxIiuTbRRaJpHsPFf4yQUMMKaPgYEC5XbU,558
+markupsafe/_constants.py,sha256=zo2ajfScG-l1Sb_52EP3MlDCqO7Y1BVHUXXKRsVDRNk,4690
+markupsafe/_native.py,sha256=d-8S_zzYt2y512xYcuSxq0NeG2DUUvG80wVdTn-4KI8,1873
+markupsafe/_speedups.cp35-win_amd64.pyd,sha256=Gl6I45geMZhMkY1_2_MkvzYKIwFyARHjzSKzI7ZGIFU,15360

+ 5 - 0
BBend-Test-JWT/venv/Lib/site-packages/MarkupSafe-1.1.1.dist-info/WHEEL

@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.33.1)
+Root-Is-Purelib: false
+Tag: cp35-cp35m-win_amd64
+

+ 1 - 0
BBend-Test-JWT/venv/Lib/site-packages/MarkupSafe-1.1.1.dist-info/top_level.txt

@@ -0,0 +1 @@
+markupsafe

+ 1 - 0
BBend-Test-JWT/venv/Lib/site-packages/Werkzeug-1.0.1.dist-info/INSTALLER

@@ -0,0 +1 @@
+pip

+ 28 - 0
BBend-Test-JWT/venv/Lib/site-packages/Werkzeug-1.0.1.dist-info/LICENSE.rst

@@ -0,0 +1,28 @@
+Copyright 2007 Pallets
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1.  Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+2.  Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+3.  Neither the name of the copyright holder nor the names of its
+    contributors may be used to endorse or promote products derived from
+    this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 128 - 0
BBend-Test-JWT/venv/Lib/site-packages/Werkzeug-1.0.1.dist-info/METADATA

@@ -0,0 +1,128 @@
+Metadata-Version: 2.1
+Name: Werkzeug
+Version: 1.0.1
+Summary: The comprehensive WSGI web application library.
+Home-page: https://palletsprojects.com/p/werkzeug/
+Author: Armin Ronacher
+Author-email: armin.ronacher@active-4.com
+Maintainer: Pallets
+Maintainer-email: contact@palletsprojects.com
+License: BSD-3-Clause
+Project-URL: Documentation, https://werkzeug.palletsprojects.com/
+Project-URL: Code, https://github.com/pallets/werkzeug
+Project-URL: Issue tracker, https://github.com/pallets/werkzeug/issues
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware
+Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
+Description-Content-Type: text/x-rst
+Provides-Extra: dev
+Requires-Dist: pytest ; extra == 'dev'
+Requires-Dist: pytest-timeout ; extra == 'dev'
+Requires-Dist: coverage ; extra == 'dev'
+Requires-Dist: tox ; extra == 'dev'
+Requires-Dist: sphinx ; extra == 'dev'
+Requires-Dist: pallets-sphinx-themes ; extra == 'dev'
+Requires-Dist: sphinx-issues ; extra == 'dev'
+Provides-Extra: watchdog
+Requires-Dist: watchdog ; extra == 'watchdog'
+
+Werkzeug
+========
+
+*werkzeug* German noun: "tool". Etymology: *werk* ("work"), *zeug* ("stuff")
+
+Werkzeug is a comprehensive `WSGI`_ web application library. It began as
+a simple collection of various utilities for WSGI applications and has
+become one of the most advanced WSGI utility libraries.
+
+It includes:
+
+-   An interactive debugger that allows inspecting stack traces and
+    source code in the browser with an interactive interpreter for any
+    frame in the stack.
+-   A full-featured request object with objects to interact with
+    headers, query args, form data, files, and cookies.
+-   A response object that can wrap other WSGI applications and handle
+    streaming data.
+-   A routing system for matching URLs to endpoints and generating URLs
+    for endpoints, with an extensible system for capturing variables
+    from URLs.
+-   HTTP utilities to handle entity tags, cache control, dates, user
+    agents, cookies, files, and more.
+-   A threaded WSGI server for use while developing applications
+    locally.
+-   A test client for simulating HTTP requests during testing without
+    requiring running a server.
+
+Werkzeug is Unicode aware and doesn't enforce any dependencies. It is up
+to the developer to choose a template engine, database adapter, and even
+how to handle requests. It can be used to build all sorts of end user
+applications such as blogs, wikis, or bulletin boards.
+
+`Flask`_ wraps Werkzeug, using it to handle the details of WSGI while
+providing more structure and patterns for defining powerful
+applications.
+
+
+Installing
+----------
+
+Install and update using `pip`_:
+
+.. code-block:: text
+
+    pip install -U Werkzeug
+
+
+A Simple Example
+----------------
+
+.. code-block:: python
+
+    from werkzeug.wrappers import Request, Response
+
+    @Request.application
+    def application(request):
+        return Response('Hello, World!')
+
+    if __name__ == '__main__':
+        from werkzeug.serving import run_simple
+        run_simple('localhost', 4000, application)
+
+
+Links
+-----
+
+-   Website: https://palletsprojects.com/p/werkzeug/
+-   Documentation: https://werkzeug.palletsprojects.com/
+-   Releases: https://pypi.org/project/Werkzeug/
+-   Code: https://github.com/pallets/werkzeug
+-   Issue tracker: https://github.com/pallets/werkzeug/issues
+-   Test status: https://dev.azure.com/pallets/werkzeug/_build
+-   Official chat: https://discord.gg/t6rrQZH
+
+.. _WSGI: https://wsgi.readthedocs.io/en/latest/
+.. _Flask: https://www.palletsprojects.com/p/flask/
+.. _pip: https://pip.pypa.io/en/stable/quickstart/
+
+

+ 101 - 0
BBend-Test-JWT/venv/Lib/site-packages/Werkzeug-1.0.1.dist-info/RECORD

@@ -0,0 +1,101 @@
+Werkzeug-1.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+Werkzeug-1.0.1.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475
+Werkzeug-1.0.1.dist-info/METADATA,sha256=d0zmVNa4UC2-nAo2A8_81oiy123D6JTGRSuY_Ymgyt4,4730
+Werkzeug-1.0.1.dist-info/RECORD,,
+Werkzeug-1.0.1.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110
+Werkzeug-1.0.1.dist-info/top_level.txt,sha256=QRyj2VjwJoQkrwjwFIOlB8Xg3r9un0NtqVHQF-15xaw,9
+werkzeug/__init__.py,sha256=rb-yPiXOjTLbtDOl5fQp5hN7oBdaoXAoQ-slAAvfZAo,502
+werkzeug/__pycache__/__init__.cpython-35.pyc,,
+werkzeug/__pycache__/_compat.cpython-35.pyc,,
+werkzeug/__pycache__/_internal.cpython-35.pyc,,
+werkzeug/__pycache__/_reloader.cpython-35.pyc,,
+werkzeug/__pycache__/datastructures.cpython-35.pyc,,
+werkzeug/__pycache__/exceptions.cpython-35.pyc,,
+werkzeug/__pycache__/filesystem.cpython-35.pyc,,
+werkzeug/__pycache__/formparser.cpython-35.pyc,,
+werkzeug/__pycache__/http.cpython-35.pyc,,
+werkzeug/__pycache__/local.cpython-35.pyc,,
+werkzeug/__pycache__/posixemulation.cpython-35.pyc,,
+werkzeug/__pycache__/routing.cpython-35.pyc,,
+werkzeug/__pycache__/security.cpython-35.pyc,,
+werkzeug/__pycache__/serving.cpython-35.pyc,,
+werkzeug/__pycache__/test.cpython-35.pyc,,
+werkzeug/__pycache__/testapp.cpython-35.pyc,,
+werkzeug/__pycache__/urls.cpython-35.pyc,,
+werkzeug/__pycache__/useragents.cpython-35.pyc,,
+werkzeug/__pycache__/utils.cpython-35.pyc,,
+werkzeug/__pycache__/wsgi.cpython-35.pyc,,
+werkzeug/_compat.py,sha256=zjufTNrhQ8BgYSGSh-sVu6iW3r3O9WzjE9j-qJobx-g,6671
+werkzeug/_internal.py,sha256=d_4AqheyS6dHMViwdc0drFrjs67ZzT6Ej2gWf-Z-Iys,14351
+werkzeug/_reloader.py,sha256=I3mg3oRQ0lLzl06oEoVopN3bN7CtINuuUQdqDcmTnEs,11531
+werkzeug/datastructures.py,sha256=AonxOcwU0TPMEzfKF1368ySULxHgxE-JE-DEAGdo2ts,100480
+werkzeug/debug/__init__.py,sha256=3RtUMc5Y9hYyK11ugHltgkQ9Dt-ViR945Vy_X5NV7zU,17289
+werkzeug/debug/__pycache__/__init__.cpython-35.pyc,,
+werkzeug/debug/__pycache__/console.cpython-35.pyc,,
+werkzeug/debug/__pycache__/repr.cpython-35.pyc,,
+werkzeug/debug/__pycache__/tbtools.cpython-35.pyc,,
+werkzeug/debug/console.py,sha256=OATaO7KHYMqpbzIFe1HeW9Mnl3wZgA3jMQoGDPn5URc,5488
+werkzeug/debug/repr.py,sha256=lIwuhbyrMwVe3P_cFqNyqzHL7P93TLKod7lw9clydEw,9621
+werkzeug/debug/shared/FONT_LICENSE,sha256=LwAVEI1oYnvXiNMT9SnCH_TaLCxCpeHziDrMg0gPkAI,4673
+werkzeug/debug/shared/console.png,sha256=bxax6RXXlvOij_KeqvSNX0ojJf83YbnZ7my-3Gx9w2A,507
+werkzeug/debug/shared/debugger.js,sha256=rOhqZMRfpZnnu6_XCGn6wMWPhtfwRAcyZKksdIxPJas,6400
+werkzeug/debug/shared/jquery.js,sha256=CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo,88145
+werkzeug/debug/shared/less.png,sha256=-4-kNRaXJSONVLahrQKUxMwXGm9R4OnZ9SxDGpHlIR4,191
+werkzeug/debug/shared/more.png,sha256=GngN7CioHQoV58rH6ojnkYi8c_qED2Aka5FO5UXrReY,200
+werkzeug/debug/shared/source.png,sha256=RoGcBTE4CyCB85GBuDGTFlAnUqxwTBiIfDqW15EpnUQ,818
+werkzeug/debug/shared/style.css,sha256=gZ9uhmb5zj3XLuT9RvnMp6jMINgQ-VVBCp-2AZbG3YQ,6604
+werkzeug/debug/shared/ubuntu.ttf,sha256=1eaHFyepmy4FyDvjLVzpITrGEBu_CZYY94jE0nED1c0,70220
+werkzeug/debug/tbtools.py,sha256=2iJ8RURUZUSbopOIehy53LnVJWx47lsHN2V2l6hc7Wc,20363
+werkzeug/exceptions.py,sha256=UTYSDkmAsH-vt8VSidlEffwqBVNXuT7bRg-_NqgUe8A,25188
+werkzeug/filesystem.py,sha256=HzKl-j0Hd8Jl66j778UbPTAYNnY6vUZgYLlBZ0e7uw0,2101
+werkzeug/formparser.py,sha256=Sto0jZid9im9ZVIf56vilCdyX-arK33wSftkYsLCnzo,21788
+werkzeug/http.py,sha256=KVRV3yFK14PJeI56qClEq4qxFdvKUQVy4C_dwuWz9_Q,43107
+werkzeug/local.py,sha256=_Tk7gB238pPWUU7habxFkZF02fiCMRVW6d62YWL1Rh0,14371
+werkzeug/middleware/__init__.py,sha256=f1SFZo67IlW4k1uqKzNHxYQlsakUS-D6KK_j0e3jjwQ,549
+werkzeug/middleware/__pycache__/__init__.cpython-35.pyc,,
+werkzeug/middleware/__pycache__/dispatcher.cpython-35.pyc,,
+werkzeug/middleware/__pycache__/http_proxy.cpython-35.pyc,,
+werkzeug/middleware/__pycache__/lint.cpython-35.pyc,,
+werkzeug/middleware/__pycache__/profiler.cpython-35.pyc,,
+werkzeug/middleware/__pycache__/proxy_fix.cpython-35.pyc,,
+werkzeug/middleware/__pycache__/shared_data.cpython-35.pyc,,
+werkzeug/middleware/dispatcher.py,sha256=_-KoMzHtcISHS7ouWKAOraqlCLprdh83YOAn_8DjLp8,2240
+werkzeug/middleware/http_proxy.py,sha256=lRjTdMmghHiZuZrS7_UJ3gZc-vlFizhBbFZ-XZPLwIA,7117
+werkzeug/middleware/lint.py,sha256=ItTwuWJnflF8xMT1uqU_Ty1ryhux-CjeUfskqaUpxsw,12967
+werkzeug/middleware/profiler.py,sha256=8B_s23d6BGrU_q54gJsm6kcCbOJbTSqrXCsioHON0Xs,4471
+werkzeug/middleware/proxy_fix.py,sha256=K5oZ3DPXOzdZi0Xba5zW7ClPOxgUuqXHQHvY2-AWCGw,6431
+werkzeug/middleware/shared_data.py,sha256=sPSRTKqtKSVBUyN8fr6jOJbdq9cdOLu6pg3gz4Y_1Xo,9599
+werkzeug/posixemulation.py,sha256=gSSiv1SCmOyzOM_nq1ZaZCtxP__C5MeDJl_4yXJmi4Q,3541
+werkzeug/routing.py,sha256=6-iZ7CKeUILYAehoKXLbmi5E6LgLbwuzUh8TNplnf5Q,79019
+werkzeug/security.py,sha256=81149MplFq7-hD4RK4sKp9kzXXejjV9D4lWBzaRyeQ8,8106
+werkzeug/serving.py,sha256=YvTqvurA-Mnj8mkqRe2kBdVr2ap4ibCq1ByQjOA6g1w,38694
+werkzeug/test.py,sha256=GJ9kxTMSJ-nB7kfGtxuROr9JGmXxDRev-2U1SkeUJGE,39564
+werkzeug/testapp.py,sha256=bHekqMsqRfVxwgFbvOMem-DYa_sdB7R47yUXpt1RUTo,9329
+werkzeug/urls.py,sha256=T8-hV_1vwhu6xhX93FwsHteK-W-kIE2orj5WoMf-WFw,39322
+werkzeug/useragents.py,sha256=TSoGv5IOvP375eK5gLLpsLQCeUgTR6sO1WftmAP_YvM,5563
+werkzeug/utils.py,sha256=hrVK4u_wi8z9viBO9bgOLlm1aaIvCpn-p2d1FeZQDEo,25251
+werkzeug/wrappers/__init__.py,sha256=S4VioKAmF_av9Ec9zQvG71X1EOkYfPx1TYck9jyDiyY,1384
+werkzeug/wrappers/__pycache__/__init__.cpython-35.pyc,,
+werkzeug/wrappers/__pycache__/accept.cpython-35.pyc,,
+werkzeug/wrappers/__pycache__/auth.cpython-35.pyc,,
+werkzeug/wrappers/__pycache__/base_request.cpython-35.pyc,,
+werkzeug/wrappers/__pycache__/base_response.cpython-35.pyc,,
+werkzeug/wrappers/__pycache__/common_descriptors.cpython-35.pyc,,
+werkzeug/wrappers/__pycache__/cors.cpython-35.pyc,,
+werkzeug/wrappers/__pycache__/etag.cpython-35.pyc,,
+werkzeug/wrappers/__pycache__/json.cpython-35.pyc,,
+werkzeug/wrappers/__pycache__/request.cpython-35.pyc,,
+werkzeug/wrappers/__pycache__/response.cpython-35.pyc,,
+werkzeug/wrappers/__pycache__/user_agent.cpython-35.pyc,,
+werkzeug/wrappers/accept.py,sha256=TIvjUc0g73fhTWX54wg_D9NNzKvpnG1X8u1w26tK1o8,1760
+werkzeug/wrappers/auth.py,sha256=Pmn6iaGHBrUyHbJpW0lZhO_q9RVoAa5QalaTqcavdAI,1158
+werkzeug/wrappers/base_request.py,sha256=4TuGlKWeKQdlq4eU94hJYcXSfWo8Rk7CS1Ef5lJ3ZM0,26012
+werkzeug/wrappers/base_response.py,sha256=JTxJZ8o-IBetpoWJqt2HFwPaNWNDAlM3_GXJe1Whw80,27784
+werkzeug/wrappers/common_descriptors.py,sha256=X2Ktd5zUWsmcd4ciaF62Dd8Lru9pLGP_XDUNukc8cXs,12829
+werkzeug/wrappers/cors.py,sha256=XMbaCol4dWTGvb-dCJBoN0p3JX91v93AIAHd7tnB3L4,3466
+werkzeug/wrappers/etag.py,sha256=XMXtyfByBsOjxwaX8U7ZtUY7JXkbQLP45oXZ0qkyTNs,12217
+werkzeug/wrappers/json.py,sha256=HvK_A4NpO0sLqgb10sTJcoZydYOwyNiPCJPV7SVgcgE,4343
+werkzeug/wrappers/request.py,sha256=QbHGqDpGPN684pnOPEokwkPESfm-NnfYM7ydOMxW_NI,1514
+werkzeug/wrappers/response.py,sha256=Oqv8TMG_dnOKTq_V30ddgkO5B7IJhkVPODvm7cbhZ3c,2524
+werkzeug/wrappers/user_agent.py,sha256=YJb-vr12cujG7sQMG9V89VsJa-03SWSenhg1W4cT0EY,435
+werkzeug/wsgi.py,sha256=ZGk85NzRyQTzkYis-xl8V9ydJgfClBdStvhzDzER2mw,34367

+ 6 - 0
BBend-Test-JWT/venv/Lib/site-packages/Werkzeug-1.0.1.dist-info/WHEEL

@@ -0,0 +1,6 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.34.2)
+Root-Is-Purelib: true
+Tag: py2-none-any
+Tag: py3-none-any
+

+ 1 - 0
BBend-Test-JWT/venv/Lib/site-packages/Werkzeug-1.0.1.dist-info/top_level.txt

@@ -0,0 +1 @@
+werkzeug

TEMPAT SAMPAH
BBend-Test-JWT/venv/Lib/site-packages/__pycache__/easy_install.cpython-35.pyc


+ 110 - 0
BBend-Test-JWT/venv/Lib/site-packages/_distutils_hack/__init__.py

@@ -0,0 +1,110 @@
+import sys
+import os
+import re
+import importlib
+import warnings
+
+
+is_pypy = '__pypy__' in sys.builtin_module_names
+
+
+def warn_distutils_present():
+    if 'distutils' not in sys.modules:
+        return
+    if is_pypy and sys.version_info < (3, 7):
+        # PyPy for 3.6 unconditionally imports distutils, so bypass the warning
+        # https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250
+        return
+    warnings.warn(
+        "Distutils was imported before Setuptools, but importing Setuptools "
+        "also replaces the `distutils` module in `sys.modules`. This may lead "
+        "to undesirable behaviors or errors. To avoid these issues, avoid "
+        "using distutils directly, ensure that setuptools is installed in the "
+        "traditional way (e.g. not an editable install), and/or make sure that "
+        "setuptools is always imported before distutils.")
+
+
+def clear_distutils():
+    if 'distutils' not in sys.modules:
+        return
+    warnings.warn("Setuptools is replacing distutils.")
+    mods = [name for name in sys.modules if re.match(r'distutils\b', name)]
+    for name in mods:
+        del sys.modules[name]
+
+
+def enabled():
+    """
+    Allow selection of distutils by environment variable.
+    """
+    which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'local')
+    return which == 'local'
+
+
+def ensure_local_distutils():
+    clear_distutils()
+    distutils = importlib.import_module('setuptools._distutils')
+    distutils.__name__ = 'distutils'
+    sys.modules['distutils'] = distutils
+
+    # sanity check that submodules load as expected
+    core = importlib.import_module('distutils.core')
+    assert '_distutils' in core.__file__, core.__file__
+
+
+def do_override():
+    """
+    Ensure that the local copy of distutils is preferred over stdlib.
+
+    See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401
+    for more motivation.
+    """
+    if enabled():
+        warn_distutils_present()
+        ensure_local_distutils()
+
+
+class DistutilsMetaFinder:
+    def find_spec(self, fullname, path, target=None):
+        if path is not None:
+            return
+
+        method_name = 'spec_for_{fullname}'.format(**locals())
+        method = getattr(self, method_name, lambda: None)
+        return method()
+
+    def spec_for_distutils(self):
+        import importlib.abc
+        import importlib.util
+
+        class DistutilsLoader(importlib.abc.Loader):
+
+            def create_module(self, spec):
+                return importlib.import_module('setuptools._distutils')
+
+            def exec_module(self, module):
+                pass
+
+        return importlib.util.spec_from_loader('distutils', DistutilsLoader())
+
+    def spec_for_pip(self):
+        """
+        Ensure stdlib distutils when running under pip.
+        See pypa/pip#8761 for rationale.
+        """
+        clear_distutils()
+        self.spec_for_distutils = lambda: None
+
+
+DISTUTILS_FINDER = DistutilsMetaFinder()
+
+
+def add_shim():
+    sys.meta_path.insert(0, DISTUTILS_FINDER)
+
+
+def remove_shim():
+    try:
+        sys.meta_path.remove(DISTUTILS_FINDER)
+    except ValueError:
+        pass

TEMPAT SAMPAH
BBend-Test-JWT/venv/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-35.pyc


TEMPAT SAMPAH
BBend-Test-JWT/venv/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-35.pyc


+ 1 - 0
BBend-Test-JWT/venv/Lib/site-packages/_distutils_hack/override.py

@@ -0,0 +1 @@
+__import__('_distutils_hack').do_override()

+ 1 - 0
BBend-Test-JWT/venv/Lib/site-packages/click-7.1.2.dist-info/INSTALLER

@@ -0,0 +1 @@
+pip

+ 28 - 0
BBend-Test-JWT/venv/Lib/site-packages/click-7.1.2.dist-info/LICENSE.rst

@@ -0,0 +1,28 @@
+Copyright 2014 Pallets
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1.  Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+2.  Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+3.  Neither the name of the copyright holder nor the names of its
+    contributors may be used to endorse or promote products derived from
+    this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 102 - 0
BBend-Test-JWT/venv/Lib/site-packages/click-7.1.2.dist-info/METADATA

@@ -0,0 +1,102 @@
+Metadata-Version: 2.1
+Name: click
+Version: 7.1.2
+Summary: Composable command line interface toolkit
+Home-page: https://palletsprojects.com/p/click/
+Maintainer: Pallets
+Maintainer-email: contact@palletsprojects.com
+License: BSD-3-Clause
+Project-URL: Documentation, https://click.palletsprojects.com/
+Project-URL: Code, https://github.com/pallets/click
+Project-URL: Issue tracker, https://github.com/pallets/click/issues
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
+Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
+
+\$ click\_
+==========
+
+Click is a Python package for creating beautiful command line interfaces
+in a composable way with as little code as necessary. It's the "Command
+Line Interface Creation Kit". It's highly configurable but comes with
+sensible defaults out of the box.
+
+It aims to make the process of writing command line tools quick and fun
+while also preventing any frustration caused by the inability to
+implement an intended CLI API.
+
+Click in three points:
+
+-   Arbitrary nesting of commands
+-   Automatic help page generation
+-   Supports lazy loading of subcommands at runtime
+
+
+Installing
+----------
+
+Install and update using `pip`_:
+
+.. code-block:: text
+
+    $ pip install -U click
+
+.. _pip: https://pip.pypa.io/en/stable/quickstart/
+
+
+A Simple Example
+----------------
+
+.. code-block:: python
+
+    import click
+
+    @click.command()
+    @click.option("--count", default=1, help="Number of greetings.")
+    @click.option("--name", prompt="Your name", help="The person to greet.")
+    def hello(count, name):
+        """Simple program that greets NAME for a total of COUNT times."""
+        for _ in range(count):
+            click.echo(f"Hello, {name}!")
+
+    if __name__ == '__main__':
+        hello()
+
+.. code-block:: text
+
+    $ python hello.py --count=3
+    Your name: Click
+    Hello, Click!
+    Hello, Click!
+    Hello, Click!
+
+
+Donate
+------
+
+The Pallets organization develops and supports Click and other popular
+packages. In order to grow the community of contributors and users, and
+allow the maintainers to devote more time to the projects, `please
+donate today`_.
+
+.. _please donate today: https://palletsprojects.com/donate
+
+
+Links
+-----
+
+-   Website: https://palletsprojects.com/p/click/
+-   Documentation: https://click.palletsprojects.com/
+-   Releases: https://pypi.org/project/click/
+-   Code: https://github.com/pallets/click
+-   Issue tracker: https://github.com/pallets/click/issues
+-   Test status: https://dev.azure.com/pallets/click/_build
+-   Official chat: https://discord.gg/t6rrQZH
+
+

+ 40 - 0
BBend-Test-JWT/venv/Lib/site-packages/click-7.1.2.dist-info/RECORD

@@ -0,0 +1,40 @@
+click-7.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+click-7.1.2.dist-info/LICENSE.rst,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475
+click-7.1.2.dist-info/METADATA,sha256=LrRgakZKV7Yg3qJqX_plu2WhFW81MzP3EqQmZhHIO8M,2868
+click-7.1.2.dist-info/RECORD,,
+click-7.1.2.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110
+click-7.1.2.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6
+click/__init__.py,sha256=FkyGDQ-cbiQxP_lxgUspyFYS48f2S_pTcfKPz-d_RMo,2463
+click/__pycache__/__init__.cpython-35.pyc,,
+click/__pycache__/_bashcomplete.cpython-35.pyc,,
+click/__pycache__/_compat.cpython-35.pyc,,
+click/__pycache__/_termui_impl.cpython-35.pyc,,
+click/__pycache__/_textwrap.cpython-35.pyc,,
+click/__pycache__/_unicodefun.cpython-35.pyc,,
+click/__pycache__/_winconsole.cpython-35.pyc,,
+click/__pycache__/core.cpython-35.pyc,,
+click/__pycache__/decorators.cpython-35.pyc,,
+click/__pycache__/exceptions.cpython-35.pyc,,
+click/__pycache__/formatting.cpython-35.pyc,,
+click/__pycache__/globals.cpython-35.pyc,,
+click/__pycache__/parser.cpython-35.pyc,,
+click/__pycache__/termui.cpython-35.pyc,,
+click/__pycache__/testing.cpython-35.pyc,,
+click/__pycache__/types.cpython-35.pyc,,
+click/__pycache__/utils.cpython-35.pyc,,
+click/_bashcomplete.py,sha256=9J98IHQYmCAr2Jup6TDshUr5FJEen-AoQCZR0K5nKxQ,12309
+click/_compat.py,sha256=AoMaYnZ-3pwtNXuHtlb6_UXsayoG0QZiHKIRy2VFezc,24169
+click/_termui_impl.py,sha256=yNktUMAdjYOU1HMkq915jR3zgAzUNtGSQqSTSSMn3eQ,20702
+click/_textwrap.py,sha256=ajCzkzFly5tjm9foQ5N9_MOeaYJMBjAltuFa69n4iXY,1197
+click/_unicodefun.py,sha256=apLSNEBZgUsQNPMUv072zJ1swqnm0dYVT5TqcIWTt6w,4201
+click/_winconsole.py,sha256=6YDu6Rq1Wxx4w9uinBMK2LHvP83aerZM9GQurlk3QDo,10010
+click/core.py,sha256=V6DJzastGhrC6WTDwV9MSLwcJUdX2Uf1ypmgkjBdn_Y,77650
+click/decorators.py,sha256=3TvEO_BkaHl7k6Eh1G5eC7JK4LKPdpFqH9JP0QDyTlM,11215
+click/exceptions.py,sha256=3pQAyyMFzx5A3eV0Y27WtDTyGogZRbrC6_o5DjjKBbw,8118
+click/formatting.py,sha256=Wb4gqFEpWaKPgAbOvnkCl8p-bEZx5KpM5ZSByhlnJNk,9281
+click/globals.py,sha256=ht7u2kUGI08pAarB4e4yC8Lkkxy6gJfRZyzxEj8EbWQ,1501
+click/parser.py,sha256=mFK-k58JtPpqO0AC36WAr0t5UfzEw1mvgVSyn7WCe9M,15691
+click/termui.py,sha256=G7QBEKIepRIGLvNdGwBTYiEtSImRxvTO_AglVpyHH2s,23998
+click/testing.py,sha256=EUEsDUqNXFgCLhZ0ZFOROpaVDA5I_rijwnNPE6qICgA,12854
+click/types.py,sha256=wuubik4VqgqAw5dvbYFkDt-zSAx97y9TQXuXcVaRyQA,25045
+click/utils.py,sha256=4VEcJ7iEHwjnFuzEuRtkT99o5VG3zqSD7Q2CVzv13WU,15940

+ 6 - 0
BBend-Test-JWT/venv/Lib/site-packages/click-7.1.2.dist-info/WHEEL

@@ -0,0 +1,6 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.34.2)
+Root-Is-Purelib: true
+Tag: py2-none-any
+Tag: py3-none-any
+

+ 1 - 0
BBend-Test-JWT/venv/Lib/site-packages/click-7.1.2.dist-info/top_level.txt

@@ -0,0 +1 @@
+click

+ 79 - 0
BBend-Test-JWT/venv/Lib/site-packages/click/__init__.py

@@ -0,0 +1,79 @@
+"""
+Click is a simple Python module inspired by the stdlib optparse to make
+writing command line scripts fun. Unlike other modules, it's based
+around a simple API that does not come with too much magic and is
+composable.
+"""
+from .core import Argument
+from .core import BaseCommand
+from .core import Command
+from .core import CommandCollection
+from .core import Context
+from .core import Group
+from .core import MultiCommand
+from .core import Option
+from .core import Parameter
+from .decorators import argument
+from .decorators import command
+from .decorators import confirmation_option
+from .decorators import group
+from .decorators import help_option
+from .decorators import make_pass_decorator
+from .decorators import option
+from .decorators import pass_context
+from .decorators import pass_obj
+from .decorators import password_option
+from .decorators import version_option
+from .exceptions import Abort
+from .exceptions import BadArgumentUsage
+from .exceptions import BadOptionUsage
+from .exceptions import BadParameter
+from .exceptions import ClickException
+from .exceptions import FileError
+from .exceptions import MissingParameter
+from .exceptions import NoSuchOption
+from .exceptions import UsageError
+from .formatting import HelpFormatter
+from .formatting import wrap_text
+from .globals import get_current_context
+from .parser import OptionParser
+from .termui import clear
+from .termui import confirm
+from .termui import echo_via_pager
+from .termui import edit
+from .termui import get_terminal_size
+from .termui import getchar
+from .termui import launch
+from .termui import pause
+from .termui import progressbar
+from .termui import prompt
+from .termui import secho
+from .termui import style
+from .termui import unstyle
+from .types import BOOL
+from .types import Choice
+from .types import DateTime
+from .types import File
+from .types import FLOAT
+from .types import FloatRange
+from .types import INT
+from .types import IntRange
+from .types import ParamType
+from .types import Path
+from .types import STRING
+from .types import Tuple
+from .types import UNPROCESSED
+from .types import UUID
+from .utils import echo
+from .utils import format_filename
+from .utils import get_app_dir
+from .utils import get_binary_stream
+from .utils import get_os_args
+from .utils import get_text_stream
+from .utils import open_file
+
+# Controls if click should emit the warning about the use of unicode
+# literals.
+disable_unicode_literals_warning = False
+
+__version__ = "7.1.2"

TEMPAT SAMPAH
BBend-Test-JWT/venv/Lib/site-packages/click/__pycache__/__init__.cpython-35.pyc


+ 0 - 0
BBend-Test-JWT/venv/Lib/site-packages/click/__pycache__/_bashcomplete.cpython-35.pyc


Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini