commit b4921f54570e110741860f2298a533a528fa4b3c
Author: RainSun <zhaoyingbo@live.cn>
Date:   Tue Apr 21 11:09:13 2020 +0800

    finish v1

diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..f723a76
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,6 @@
+FROM python:3.7-alpine
+
+COPY requirements.txt /app/requirements.txt
+WORKDIR /app
+RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
+COPY . /app
\ No newline at end of file
diff --git a/ReadMe.md b/ReadMe.md
new file mode 100644
index 0000000..f81e89e
--- /dev/null
+++ b/ReadMe.md
@@ -0,0 +1,53 @@
+# db电话簿
+## 服务器配置
+```js
+// 安装venv
+python3 -m venv venv
+// 启动venv
+. venv/bin/activate
+// 升级pip
+pip install --upgrade pip
+// 根据依赖文件安装环境
+pip install -r requirements.txt
+// 设置全局变量
+export FLASK_APP=phonebook.py
+export FLASK_ENV=development
+flask run --host=0.0.0.0 -p 80
+// 启动永久服务
+gunicorn phonebook:app -c gunicorn.conf.py
+// 查看已启动服务
+pstree -ap|grep gunicorn
+// 关闭某服务
+kill (pid)
+//关闭venv
+deactivate 
+// 创建当前环境的依赖文件
+pip freeze > requirements.txt
+```
+
+## 错误码
+/login
+450:没用手机号登录过教务
+422:账号或者密码错误
+400:数据不合法
+510:数据库查询失败
+511:教务挂了
+512:未注册
+/sign
+400:数据不合法
+510:数据库插入失败
+511:已注册过,无需再次注册
+512:数据库查询失败
+/del
+400:数据不合法
+510:数据库删除失败
+/update
+400:数据不合法
+510:数据库覆写失败
+/get
+400:数据不合法
+510:数据库查询失败
+511:用户认证失败
+512:数据库查询失败
+
+docker run -it --name beta -v /root/data/phonebook:/app -p 127.0.0.1:6000:80 --network=lacus lacus/flask_env /bin/sh
\ No newline at end of file
diff --git a/go.sh b/go.sh
new file mode 100644
index 0000000..5d16001
--- /dev/null
+++ b/go.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+echo start
+gunicorn phonebook:app -c gunicorn.conf.py
\ No newline at end of file
diff --git a/gunicorn.conf.py b/gunicorn.conf.py
new file mode 100644
index 0000000..80f8002
--- /dev/null
+++ b/gunicorn.conf.py
@@ -0,0 +1,8 @@
+# 并行工作线程数
+workers = 4
+bind = '0.0.0.0:80'
+daemon = True
+timeout = 120
+accesslog = './logs/acess.log'
+errorlog = './logs/error.log'
+autostart = True
\ No newline at end of file
diff --git a/lib/__init__.py b/lib/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/lib/allFunctions.py b/lib/allFunctions.py
new file mode 100644
index 0000000..cde5e07
--- /dev/null
+++ b/lib/allFunctions.py
@@ -0,0 +1,202 @@
+from utils import randomId, md5Check, connection, signCode
+from db import col
+import json
+
+# 前端传来的参数应为 cid, pwd, sign
+
+
+def manageLogin(request):
+    try:
+        data = json.loads(request.form['data'])
+        if not data.__contains__('cid'):
+            raise Exception
+        if not data.__contains__('pwd'):
+            raise Exception
+        if not data.__contains__('sign'):
+            raise Exception
+        if md5Check(data):
+            # 数据校验通过
+            try:
+                # 查询用户信息
+                user_info = col().find_one({'cid': data['cid']}, {"_id": 0})
+                if user_info:
+                    # 获取到用户正常返回
+                    if user_info['pwd'] == signCode(data['pwd']):
+                        return {'user_info': user_info}, 200
+                    else:
+                        return '账号或密码错误', 422
+                else:
+                    # 数据库没有用户信息,查询一下教务
+                    return connection(data['cid'], data['pwd'])
+            except Exception as e:
+                print(e)
+                return '数据库查询失败', 510
+        else:
+            return '数据不合法', 400
+    except Exception as e:
+        print(e)
+        return '数据不合法', 400
+
+# 前端传来的参数应为 cid, pwd, sign, sex, tel, department, position, adds, qq, wx
+
+
+def manageSign(request):
+    try:
+        data = json.loads(request.form['data'])
+        if not data.__contains__('cid'):
+            raise Exception
+        if not data.__contains__('pwd'):
+            raise Exception
+        if not data.__contains__('sign'):
+            raise Exception
+        if not data.__contains__('sex'):
+            raise Exception
+        if not data.__contains__('tel'):
+            raise Exception
+        if not data.__contains__('department'):
+            raise Exception
+        if not data.__contains__('position'):
+            raise Exception
+        if not data.__contains__('adds'):
+            raise Exception
+        if not data.__contains__('qq'):
+            raise Exception
+        if not data.__contains__('wx'):
+            raise Exception
+        if md5Check(data):
+            # 数据校验通过
+            try:
+                user_info = col().find_one({'cid': data['cid']}, {"_id": 0})
+                if user_info:
+                    return '已注册过,无需再次注册', 511
+                else:
+                    try:
+                        data.pop('sign')
+                        data['pwd'] = signCode(data['pwd'])
+                        data['openid'] = randomId()
+                        data_cache = data.copy()
+                        # 插入用户信息
+                        col().insert_one(data)
+                        return {'user_info': data_cache}, 200
+                    except Exception as e:
+                        print(e)
+                        return '数据库插入失败', 510
+            except Exception as e:
+                print(e)
+                return '数据库查询失败', 512
+        else:
+            return '数据不合法', 400
+    except Exception as e:
+        print(e)
+        return '数据不合法', 400
+
+# 前端传来的参数应为 openid sign
+
+
+def manageDel(request):
+    try:
+        data = json.loads(request.form['data'])
+        if not data.__contains__('openid'):
+            raise Exception
+        if not data.__contains__('sign'):
+            raise Exception
+        if md5Check(data):
+            # 数据校验通过
+            try:
+                col().remove({'openid': data['openid']})
+                return 'OK', 200
+            except Exception as e:
+                print(e)
+                return '数据库删除失败', 510
+        else:
+            return '数据不合法', 400
+    except Exception as e:
+        print(e)
+        return '数据不合法', 400
+
+# 前端传来的参数应为 cid, pwd, sign, sex, tel, department, position, adds, qq, wx, openid, id, name
+
+
+def manageUpdate(request):
+    try:
+        data = json.loads(request.form['data'])
+        if not data.__contains__('cid'):
+            raise Exception
+        if not data.__contains__('name'):
+            raise Exception
+        if not data.__contains__('id'):
+            raise Exception
+        if not data.__contains__('pwd'):
+            raise Exception
+        if not data.__contains__('sign'):
+            raise Exception
+        if not data.__contains__('sex'):
+            raise Exception
+        if not data.__contains__('tel'):
+            raise Exception
+        if not data.__contains__('department'):
+            raise Exception
+        if not data.__contains__('position'):
+            raise Exception
+        if not data.__contains__('adds'):
+            raise Exception
+        if not data.__contains__('qq'):
+            raise Exception
+        if not data.__contains__('wx'):
+            raise Exception
+        if not data.__contains__('openid'):
+            raise Exception
+        if md5Check(data):
+            # 数据校验通过
+            try:
+                data.pop('sign')
+                data['pwd'] = signCode(data['pwd'])
+                # 更新用户信息
+                col().update({'openid': data['openid']}, data)
+                return 'OK', 200
+            except Exception as e:
+                print(e)
+                return '数据库覆写失败', 510
+        else:
+            return '数据不合法', 400
+    except Exception as e:
+        print(e)
+        return '数据不合法', 400
+
+# 前端传来的参数应为 openid, sign
+
+
+def manageGet(request):
+    try:
+        data = json.loads(request.form['data'])
+        if not data.__contains__('openid'):
+            raise Exception
+        if not data.__contains__('sign'):
+            raise Exception
+        if md5Check(data):
+            # 数据校验通过
+            try:
+                # 查询用户信息
+                user_info = col().find_one(
+                    {'openid': data['openid']}, {"_id": 0})
+                if user_info:
+                    user_list = []
+                    try:
+                        for i in col().find({}, {"sex": 1, "tel": 1, "department": 1, "position": 1, "adds": 1, "qq": 1, "wx": 1, "id": 1, "name": 1}):
+                            if i.get('_id'):
+                                i.pop('_id')
+                            user_list.append(i)
+                        return {'user_list': user_list}, 200
+                    except Exception as e:
+                        print(e)
+                        return ('数据库查询失败', 512)
+                else:
+                    return '用户认证失败', 511
+            except Exception as e:
+                print(e)
+                return '数据库查询失败', 510
+        else:
+            return '数据不合法', 400
+    except Exception as e:
+        print(e)
+        return '数据不合法', 400
diff --git a/lib/db.py b/lib/db.py
new file mode 100644
index 0000000..daac1a0
--- /dev/null
+++ b/lib/db.py
@@ -0,0 +1,9 @@
+from pymongo import MongoClient
+from bson import ObjectId, json_util
+
+# 获取数据集
+def col():
+    # 链接数据库
+    conn = MongoClient('mongodb://pb:wO0pM5rD9eP3@mongo:27017/pb')
+    return conn.pb.user
+
diff --git a/lib/utils.py b/lib/utils.py
new file mode 100644
index 0000000..260a980
--- /dev/null
+++ b/lib/utils.py
@@ -0,0 +1,82 @@
+import json
+import requests
+from urllib.parse import quote
+import base64
+from bs4 import BeautifulSoup
+import random
+from hashlib import md5
+import datetime
+
+# 链接教务获取信息
+def connection(username,password):
+    try:
+        s = requests.Session()
+        # 获取统一身份系统的网页
+        r = s.get(url='http://mysso-cust-edu-cn-s.webvpn.cust.edu.cn:8118/cas/login?service=https%3A%2F%2Fwebvpn.cust.edu.cn%2Fauth%2Fcas_validate%3Fentry_id%3D1')
+        # soup = BeautifulSoup(r.text,'lxml')
+        soup = BeautifulSoup(r.text,'html.parser')
+        execution=soup.find_all(name='input')[6]['value']
+        formdata={
+            'username':username,
+            'password':password,
+            'execution':execution,
+            '_eventId':'submit',
+            'geolocation':''
+        }
+        r = s.post(url='http://mysso-cust-edu-cn-s.webvpn.cust.edu.cn:8118/cas/login?service=https%3A%2F%2Fwebvpn.cust.edu.cn%2Fauth%2Fcas_validate%3Fentry_id%3D1',data=formdata)   
+        soup=BeautifulSoup(r.text,'html.parser')
+        flag = soup.find(name='title')
+        if(flag.text=="手机号设置"):
+            return ('没用手机号登陆过教务', 450)
+        r = s.get(url='http://portal-cust-edu-cn-s.webvpn.cust.edu.cn:8118/custp/index')
+        soup=BeautifulSoup(r.text,'html.parser')
+        try:
+            ip = soup.findAll(name='a')[7]['href'][7:].split("-")
+        except:
+            return ('账号或密码错误', 422)
+        r = s.get(url='http://mysso-cust-edu-cn-s.webvpn.cust.edu.cn:8118/cas/login?service=http://'+ip[0]+'.'+ip[1]+'.'+ip[2]+'.'+ip[3]+':8080/welcome',allow_redirects=False)
+        ticket = r.headers['Location'][68:]
+        asp_net_sessionid_param = {'Ticket':ticket,'Url':'http://'+ip[0]+'.'+ip[1]+'.'+ip[2]+'.'+ip[3]+':8080/welcome'}
+        asp_net_sessionid_param = base64.b64encode(quote(json.dumps(asp_net_sessionid_param)).encode('utf-8')).decode('utf-8')
+        asp_net_sessionid_param = {'param':asp_net_sessionid_param}
+        headers = {'Content-Type': 'application/json'}
+        r = s.post(url='http://'+ip[0]+'-'+ip[1]+'-'+ip[2]+'-'+ip[3]+'-8080-p.webvpn.cust.edu.cn:8118/api/LoginApi/LGSSOLocalLogin?sf_request_type=ajax',data=json.dumps(asp_net_sessionid_param),headers=headers)
+        data = json.loads(r.content.decode('utf-8'))
+        student_name = data['data']['StudentDto']['XM']
+        student_id = data['data']['StudentDto']['XH']
+        return ({'name': student_name, 'id': student_id}, 512)
+    except Exception as e:
+        print(e)
+        return ('教务挂了', 511)
+
+# 给str签名,用于加密密码
+def signCode(code):
+    d = str(code)
+    d = d.replace(' ', '')
+    md = md5()
+    md.update(d.encode('utf-8'))
+    r = md.hexdigest().upper()
+    return r
+
+# 生成唯一不重名字符串
+def randomId():
+    nowTime = datetime.datetime.now().strftime("%Y%m%d%H%M%S")  # 生成当前时间
+    randomNum = random.randint(0, 100)  # 生成的随机整数n,其中0<=n<=100
+    if randomNum <= 10:
+        randomNum = str(0) + str(randomNum)
+    uniqueNum = str(nowTime) + str(randomNum)
+    return uniqueNum
+
+# MD5 校验
+def md5Check(data):
+    d = data.copy()
+    try:
+        d.pop('sign')
+    except KeyError:
+        pass
+    d = str(d)
+    d = d.replace(' ', '')
+    md = md5()
+    md.update(d.encode('utf-8'))
+    r = md.hexdigest().upper()
+    return r == data['sign']
\ No newline at end of file
diff --git a/phonebook.py b/phonebook.py
new file mode 100644
index 0000000..814126b
--- /dev/null
+++ b/phonebook.py
@@ -0,0 +1,46 @@
+import sys
+sys.path.append('./lib')
+from flask import Flask, request, redirect
+from flask_cors import CORS
+from allFunctions import manageLogin, manageSign, manageUpdate, manageDel, manageGet
+
+app = Flask(__name__)
+CORS(app, resources=r'/*')
+
+# 测试
+@app.route('/v1/')
+def base():
+    return 'Hello! Glad to serve you.'
+
+# 登录
+@app.route('/v1/login', methods=['POST'])
+def login():
+    return manageLogin(request)
+
+# 注册
+@app.route('/v1/sign', methods=['POST'])
+def sign():
+    return manageSign(request)
+
+# 修改
+@app.route('/v1/update', methods=['POST'])
+def update():
+    return manageUpdate(request)
+
+# 获取
+@app.route('/v1/get', methods=['POST'])
+def get():
+    return manageGet(request)
+
+# 删除
+@app.route('/v1/del', methods=['POST'])
+def dele():
+    return manageDel(request)
+
+# 访问拦截器转发到根路由
+@app.errorhandler(404)
+def miss(e):
+    return redirect('/v1/')
+
+if __name__ == '__main__':
+    app.run(host="0.0.0.0", debug=True, port="80")
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..7248c1a
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,18 @@
+beautifulsoup4==4.8.2
+bs4==0.0.1
+certifi==2019.11.28
+chardet==3.0.4
+Click==7.0
+Flask==1.1.1
+Flask-Cors==3.0.8
+gunicorn==20.0.4
+idna==2.8
+itsdangerous==1.1.0
+Jinja2==2.10.3
+MarkupSafe==1.1.1
+pymongo==3.10.1
+requests==2.22.0
+six==1.14.0
+soupsieve==1.9.5
+urllib3==1.25.7
+Werkzeug==0.16.0