├── .gitignore ├── Dockerfile ├── PartTimeJobPlatform.py ├── README.md ├── app ├── __init__.py ├── blockchain │ ├── __init__.py │ ├── base.py │ ├── jobinfo.py │ ├── tx.py │ └── userinfo.py ├── controllers │ ├── JobController.py │ ├── TxController.py │ ├── UserController.py │ └── __init__.py ├── db │ ├── __init__.py │ ├── mongodb.py │ └── redisdb.py ├── modules │ └── __init__.py ├── routersjobs.py ├── routerstxs.py ├── routersuser.py ├── routersutil.py ├── routes.py ├── static │ ├── css │ │ └── .gitkeep │ ├── imgs │ │ ├── .gitkeep │ │ └── favicon.png │ ├── indextest.html │ └── js │ │ └── .gitkeep ├── templates │ ├── 404.html │ ├── index.html │ ├── layout.html │ └── login.html └── utils │ ├── __init__.py │ ├── hashutil.py │ ├── jsonutil.py │ └── util.py ├── chaincode ├── JobInfo │ └── JobInfo.go ├── TX │ └── TX.go └── UserInfo │ └── UserInfo.go ├── config.ini ├── config.py ├── debug-start.sh ├── frontend ├── .gitkeep ├── install_frontend.sh ├── npm-debug.log └── start_front_server.sh ├── instance ├── __init__.py └── config.py ├── logs └── .gitkeep ├── manage.py ├── nginx.conf ├── nginx └── nginx.conf ├── redis-install.sh ├── refresh_config.sh ├── requirement.txt └── startserver.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | .idea/ 3 | 4 | frontend/PartTimePlatform-frontend/ 5 | frontend/PartTimePlatform-frontend/.git/ 6 | frontend/PartTimePlatform-frontend/dist/ 7 | frontend/PartTimePlatform-frontend/node_modules/ 8 | 9 | logs/* 10 | !logs/.gitkeep 11 | app/others/uwsgi.log 12 | *.txt 13 | !requirement.txt 14 | *.xlsx 15 | nohup.out -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tiangolo/uwsgi-nginx:latest 2 | 3 | MAINTAINER Sebastian Ramirez 4 | 5 | # change to local 6 | ENV TZ=Asia/Shanghai 7 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone 8 | 9 | # Add app configuration to Nginx 10 | # TODO check as nginx deamon 11 | # COPY nginx/nginx.conf /etc/nginx/nginx.conf 12 | COPY nginx.conf /etc/nginx/conf.d/ 13 | 14 | # install redis and start 15 | COPY redis-install.sh /tmp/ 16 | RUN chmod +x /tmp/redis-install.sh 17 | RUN /bin/bash /tmp/redis-install.sh 18 | 19 | COPY startserver.sh /tmp/ 20 | RUN chmod +x /tmp/startserver.sh 21 | 22 | # front end 23 | RUN apt-get install -y curl 24 | RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - 25 | RUN apt-get install -y nodejs 26 | 27 | RUN dpkg-divert --local --rename --add /etc/init.d/mongod 28 | RUN ln -s /bin/true /etc/init.d/mongod 29 | ## Import MongoDB public GPG key AND create a MongoDB list file 30 | RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10 31 | RUN echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | tee /etc/apt/sources.list.d/10gen.list 32 | RUN apt-get update 33 | 34 | # install mongodb 35 | # Create the MongoDB data directory 36 | RUN mkdir -p /data/db 37 | RUN apt-get install -y apt-utils 38 | RUN apt-get install -y mongodb-org 39 | 40 | COPY requirement.txt /tmp/ 41 | RUN pip install -r /tmp/requirement.txt 42 | 43 | #RUN frontend/install_frontend.sh init 44 | 45 | ENTRYPOINT ["/bin/bash"] 46 | -------------------------------------------------------------------------------- /PartTimeJobPlatform.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | 6 | @app.route('/') 7 | def hello_world(): 8 | return 'Hello World!' 9 | 10 | 11 | if __name__ == '__main__': 12 | app.run() 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 同嘉-基于区块链的信用兼职平台 2 | 3 | ## 简介 4 | 本作品基于hyperledger fabric搭建一个互利互惠的学生兼职中介联盟,改变当前信用成本高,虚假信息,信息不透明,效率低下的缺点,利用区块链的不可篡改性,透明性,自动执行的智能合约,响应政府的“互联网+”战略,迎合市场的需求,消除黑中介,黑公司,打造一个更好的学生兼职环境。 5 | 本作品基于学生兼职中存在的诸多痛点,利用中介之间的竞争关系来达到用人公司、中介、学生三方之间的利益互惠,构建一个良性的信用生态。同时引入信用评级体系,学生、中介和用人公司三方互评,相互制约,使得不良中介、公司和学生很难在该生态中生存下去。使得学生可以获得更多更安全的招聘信息,公司能够更快地招聘到优质的人才。 6 | -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from flask import Flask, session 5 | import os 6 | import logging 7 | from flask_redis import FlaskRedis 8 | 9 | 10 | def create_app(): 11 | inner_app = Flask(__name__, instance_relative_config=True) 12 | # 加载配置 从根项目下的config.py加载 13 | inner_app.config.from_object('config') 14 | # 加载配置 从 instance/config.py 加载,需要在Flask(__name__, instance_relative_config=True(加这个参数)),可覆盖上面配置 15 | inner_app.config.from_pyfile('config.py') 16 | # log 17 | handler = __create_log_handler(inner_app) 18 | inner_app.logger.addHandler(handler) 19 | # init redis 20 | redis_store = FlaskRedis(inner_app) 21 | return inner_app, redis_store 22 | 23 | 24 | def __create_log_handler(app): 25 | path = os.path.realpath(__file__) 26 | log_path = os.path.dirname(path) + '/../logs/flask.log' 27 | logging_format = logging.Formatter( 28 | '%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)s - %(message)s') 29 | 30 | if app.debug: 31 | handler = logging.FileHandler(log_path, mode='w', encoding='UTF-8') 32 | else: 33 | handler = logging.FileHandler(log_path, mode='a', encoding='UTF-8') 34 | handler.setLevel(logging.ERROR) 35 | 36 | handler.setFormatter(logging_format) 37 | return handler 38 | 39 | 40 | app, redis_store = create_app() 41 | logger = app.logger 42 | 43 | # import redis 44 | # redisdb = redis.StrictRedis(host='localhost', port=6379, db=0) 45 | # redisdb.zrangebyscore() 46 | 47 | from app.routes import * 48 | -------------------------------------------------------------------------------- /app/blockchain/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import requests 4 | import json 5 | from copy import deepcopy 6 | import traceback 7 | from hyperledger.client import Client 8 | from .. import app 9 | 10 | # BLOCKCHAIN_URL = app.config['BLOCKCHAIN_URL'] 11 | 12 | 13 | # 适合用于区块信息展示 14 | # blockchain_client = Client(base_url=BLOCKCHAIN_URL) 15 | JOBINFO_URL = app.config["BLOCKCHAIN_JOBINFO_URL"] 16 | 17 | 18 | def test_conn(): 19 | r = requests.get(JOBINFO_URL) 20 | return r 21 | 22 | 23 | def main(): 24 | pass 25 | 26 | 27 | if __name__ == '__main__': 28 | main() 29 | -------------------------------------------------------------------------------- /app/blockchain/base.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import json 4 | import requests 5 | import traceback 6 | from flask import abort 7 | 8 | 9 | class BlockChain(object): 10 | # def to_blockchain(self, func, **params): 11 | # # self.dump_to_dict() 12 | # raise NotImplementedError("Must impl this func and return a list") 13 | 14 | # @classmethod 15 | # def from_blockchain(cls): 16 | # # TODO retrieve from blockchain 17 | # data = {} 18 | # bcid = "" 19 | # return cls.load_from_dict(data, bcid) 20 | 21 | @staticmethod 22 | def post(url, data): 23 | try: 24 | r = requests.post(url, json=data) 25 | data = r.json() 26 | print data 27 | if 'result' not in data: 28 | print "blockchain access return error!" 29 | return None 30 | return data['result'] if data['result']['status'] == 'OK' else None 31 | except ValueError, e: 32 | print "json parse error!" 33 | print e 34 | traceback.print_exc() 35 | abort(500, u"blockchain 返回数据异常,无法被json解析") 36 | return None 37 | except Exception, e: 38 | print "request error!" 39 | print e 40 | traceback.print_exc() 41 | abort(500, u"访问 blockchain 异常") 42 | return None 43 | 44 | @staticmethod 45 | def invoke(url, data): 46 | return BlockChain.post(url, data) 47 | 48 | @staticmethod 49 | def query(url, data): 50 | r = BlockChain.post(url, data) 51 | if r is None: 52 | return None 53 | try: 54 | # print json.loads(r['message']) 55 | return json.loads(r['message']) 56 | except Exception, e: 57 | print "json parse error for message!" 58 | print e 59 | traceback.print_exc() 60 | return None 61 | 62 | pass 63 | 64 | 65 | def main(): 66 | pass 67 | 68 | 69 | if __name__ == '__main__': 70 | main() 71 | -------------------------------------------------------------------------------- /app/blockchain/jobinfo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # !/usr/bin/env python 5 | # -*- coding: utf-8 -*- 6 | 7 | from copy import deepcopy 8 | import json 9 | from base import BlockChain 10 | from app import app 11 | 12 | JOBINFO_URL = app.config["BLOCKCHAIN_JOBINFO_URL"] 13 | CHAINCODE_ID = app.config["BLOCKCHAIN_JOBINFO_CHAINCODE_ID"] 14 | 15 | 16 | class BlockChainJobInfoMixIn(object): 17 | @classmethod 18 | def from_blockchain(cls, jobid): 19 | data = deepcopy(TX_QUERY_DATA) 20 | data["params"]["ctorMsg"]["function"] = "queryJobInfo" 21 | data["params"]["ctorMsg"]["args"] = [jobid] 22 | ret = BlockChain.query(JOBINFO_URL, data) 23 | print ret 24 | return cls.load_from_dict(ret) if ret is not None else None 25 | 26 | def bc_create(self): 27 | data = deepcopy(JOBINFO_INVOKE_DATA) 28 | data["params"]["ctorMsg"]["function"] = "add" 29 | data["params"]["ctorMsg"]["args"] = self.blockchain_create_params() 30 | # print "++++++++" 31 | # print data["params"]["ctorMsg"]["args"] 32 | # print "++++++++" 33 | r = BlockChain.invoke(JOBINFO_URL, data) 34 | print json.dumps(data) 35 | print r 36 | 37 | def blockchain_create_params(self): 38 | raise NotImplementedError("Must impl this func and return a list") 39 | 40 | def bc_update(self): 41 | data = deepcopy(JOBINFO_INVOKE_DATA) 42 | data["params"]["ctorMsg"]["function"] = "edit" 43 | data["params"]["ctorMsg"]["args"] = self.blockchain_update_params() 44 | BlockChain.invoke(JOBINFO_URL, data) 45 | 46 | def blockchain_update_params(self): 47 | raise NotImplementedError("Must impl this func and return a list") 48 | 49 | def bc_delete(self): 50 | data = deepcopy(JOBINFO_INVOKE_DATA) 51 | data["params"]["ctorMsg"]["function"] = "delete" 52 | data["params"]["ctorMsg"]["args"] = self.blockchain_delete_params() 53 | BlockChain.invoke(JOBINFO_URL, data) 54 | 55 | def blockchain_delete_params(self): 56 | raise NotImplementedError("Must impl this func and return a list") 57 | 58 | def bc_add_tx(self, txid): 59 | data = deepcopy(JOBINFO_INVOKE_DATA) 60 | data["params"]["ctorMsg"]["function"] = "addTX" 61 | data["params"]["ctorMsg"]["args"] = self.blockchain_addtx_params(txid) 62 | BlockChain.invoke(JOBINFO_URL, data) 63 | 64 | def blockchain_addtx_params(self, txid): 65 | raise NotImplementedError("Must impl this func and return a list") 66 | 67 | def bc_add_total_applied(self): 68 | data = deepcopy(JOBINFO_INVOKE_DATA) 69 | data["params"]["ctorMsg"]["function"] = "addTotalApplied" 70 | data["params"]["ctorMsg"]["args"] = self.blockchain_jobrelated_params() 71 | BlockChain.invoke(JOBINFO_URL, data) 72 | 73 | def bc_add_total_wait_check(self): 74 | data = deepcopy(JOBINFO_INVOKE_DATA) 75 | data["params"]["ctorMsg"]["function"] = "addTotalWaitCheck" 76 | data["params"]["ctorMsg"]["args"] = self.blockchain_jobrelated_params() 77 | BlockChain.invoke(JOBINFO_URL, data) 78 | 79 | def bc_add_total_hired(self): 80 | data = deepcopy(JOBINFO_INVOKE_DATA) 81 | data["params"]["ctorMsg"]["function"] = "addTotalHired" 82 | data["params"]["ctorMsg"]["args"] = self.blockchain_jobrelated_params() 83 | BlockChain.invoke(JOBINFO_URL, data) 84 | 85 | # def bc_add_total_settled(self): 86 | # data = deepcopy(JOBINFO_INVOKE_DATA) 87 | # data["params"]["ctorMsg"]["function"] = "addTotalSettled" 88 | # data["params"]["ctorMsg"]["args"] = self.blockchain_jobrelated_params() 89 | # BlockChain.invoke(JOBINFO_URL, data) 90 | 91 | def blockchain_jobrelated_params(self): 92 | raise NotImplementedError("Must impl this func and return a list") 93 | 94 | pass 95 | 96 | 97 | JOBINFO_INVOKE = """ 98 | { 99 | "jsonrpc": "2.0", 100 | "method": "invoke", 101 | "params": { 102 | "type": 1, 103 | "chaincodeID": { 104 | "name": "%s" 105 | }, 106 | "ctorMsg": { 107 | "function": null, 108 | "args": [ 109 | 110 | ] 111 | }, 112 | "secureContext": "user_type1_0" 113 | }, 114 | "id": 0 115 | } 116 | """ % CHAINCODE_ID 117 | JOBINFO_INVOKE_DATA = json.loads(JOBINFO_INVOKE) 118 | 119 | JOBINFO_QUERY = """ 120 | { 121 | "jsonrpc": "2.0", 122 | "method": "query", 123 | "params": { 124 | "type": 1, 125 | "chaincodeID": { 126 | "name": "%s" 127 | }, 128 | "ctorMsg": { 129 | "function": "queryJobInfo", 130 | "args": [ 131 | 132 | ] 133 | }, 134 | "secureContext": "user_type1_0" 135 | }, 136 | "id": 0 137 | } 138 | """ % CHAINCODE_ID 139 | TX_QUERY_DATA = json.loads(JOBINFO_QUERY) 140 | 141 | 142 | def main(): 143 | pass 144 | 145 | 146 | if __name__ == '__main__': 147 | main() 148 | -------------------------------------------------------------------------------- /app/blockchain/tx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # !/usr/bin/env python 5 | # -*- coding: utf-8 -*- 6 | 7 | from copy import deepcopy 8 | import json 9 | from base import BlockChain 10 | from app import app 11 | 12 | TX_URL = app.config["BLOCKCHAIN_TX_URL"] 13 | CHAINCODE_ID = app.config["BLOCKCHAIN_TX_CHAINCODE_ID"] 14 | 15 | 16 | class BlockChainTxMixIn(object): 17 | @classmethod 18 | def from_blockchain(cls, txid): 19 | data = deepcopy(TX_QUERY_DATA) 20 | data["params"]["ctorMsg"]["function"] = "queryTxInfo" 21 | data["params"]["ctorMsg"]["args"] = [txid] 22 | ret = BlockChain.query(TX_URL, data) 23 | print "qurey:" 24 | print json.dumps(ret) 25 | return cls.load_from_dict(ret) if ret is not None else None 26 | 27 | def bc_create(self): 28 | data = deepcopy(TX_INVOKE_DATA) 29 | data["params"]["ctorMsg"]["function"] = "create" 30 | data["params"]["ctorMsg"]["args"] = self.blockchain_create_params() 31 | # print "++++++++++++" 32 | # print json.dumps(data) 33 | # print "+++++++++" 34 | ret = BlockChain.invoke(TX_URL, data) 35 | print "+++++++++" 36 | print ret 37 | 38 | def blockchain_create_params(self): 39 | raise NotImplementedError("Must impl this func and return a list") 40 | 41 | def bc_artificial_check(self, result): 42 | data = deepcopy(TX_INVOKE_DATA) 43 | data["params"]["ctorMsg"]["function"] = "artificialCheck" 44 | data["params"]["ctorMsg"]["args"] = self.blockchain_check_params(result) 45 | ret = BlockChain.invoke(TX_URL, data) 46 | print "+++++++++" 47 | print ret 48 | 49 | def blockchain_check_params(self, result): 50 | raise NotImplementedError("Must impl this func and return a list") 51 | 52 | def bc_evaluate(self, userid, score): 53 | data = deepcopy(TX_INVOKE_DATA) 54 | data["params"]["ctorMsg"]["function"] = "evaluate" 55 | data["params"]["ctorMsg"]["args"] = self.blockchain_evaluate_params(userid, score) 56 | ret = BlockChain.invoke(TX_URL, data) 57 | print "+++++++++" 58 | print ret 59 | 60 | def blockchain_evaluate_params(self, userid, score): 61 | raise NotImplementedError("Must impl this func and return a list") 62 | 63 | pass 64 | 65 | 66 | TX_INVOKE = """ 67 | { 68 | "jsonrpc": "2.0", 69 | "method": "invoke", 70 | "params": { 71 | "type": 1, 72 | "chaincodeID": { 73 | "name": "%s" 74 | }, 75 | "ctorMsg": { 76 | "function": null, 77 | "args": [ 78 | 79 | ] 80 | }, 81 | "secureContext": "user_type1_0" 82 | }, 83 | "id": 0 84 | } 85 | """ % CHAINCODE_ID 86 | TX_INVOKE_DATA = json.loads(TX_INVOKE) 87 | 88 | TX_QUERY = """ 89 | { 90 | "jsonrpc": "2.0", 91 | "method": "query", 92 | "params": { 93 | "type": 1, 94 | "chaincodeID": { 95 | "name": "%s" 96 | }, 97 | "ctorMsg": { 98 | "function": "queryTxInfo", 99 | "args": [ 100 | 101 | ] 102 | }, 103 | "secureContext": "user_type1_0" 104 | }, 105 | "id": 0 106 | } 107 | """ % CHAINCODE_ID 108 | TX_QUERY_DATA = json.loads(TX_QUERY) 109 | 110 | 111 | def main(): 112 | pass 113 | 114 | 115 | if __name__ == '__main__': 116 | main() 117 | -------------------------------------------------------------------------------- /app/blockchain/userinfo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from copy import deepcopy 5 | import json 6 | from base import BlockChain 7 | from app import app 8 | 9 | USERINFO_URL = app.config["BLOCKCHAIN_USERINFO_URL"] 10 | CHAINCODE_ID = app.config["BLOCKCHAIN_USERINFO_CHAINCODE_ID"] 11 | 12 | 13 | class BlockChainUserInfoMixIn(object): 14 | @classmethod 15 | def from_blockchain(cls, userid): 16 | data = deepcopy(USERINFO_QUERY_DATA) 17 | data["params"]["ctorMsg"]["function"] = "queryUserInfo" 18 | data["params"]["ctorMsg"]["args"] = [userid] 19 | ret = BlockChain.query(USERINFO_URL, data) 20 | print '+++++++++' 21 | print ret 22 | print '+++++++++' 23 | return cls.load_from_dict(ret) if ret is not None else None 24 | 25 | def bc_create(self): 26 | data = deepcopy(USERINFO_INVOKE_DATA) 27 | data["params"]["ctorMsg"]["function"] = "add" 28 | data["params"]["ctorMsg"]["args"] = self.blockchain_create_params() 29 | # print json.dumps(data) 30 | r = BlockChain.invoke(USERINFO_URL, data) 31 | # print r.text 32 | 33 | def blockchain_create_params(self): 34 | raise NotImplementedError("Must impl this func and return a list") 35 | 36 | def bc_update(self): 37 | data = deepcopy(USERINFO_INVOKE_DATA) 38 | data["params"]["ctorMsg"]["function"] = "edit" 39 | data["params"]["ctorMsg"]["args"] = self.blockchain_update_params() 40 | BlockChain.invoke(USERINFO_URL, data) 41 | 42 | def blockchain_update_params(self): 43 | raise NotImplementedError("Must impl this func and return a list") 44 | 45 | def bc_delete(self): 46 | data = deepcopy(USERINFO_INVOKE_DATA) 47 | data["params"]["ctorMsg"]["function"] = "delete" 48 | data["params"]["ctorMsg"]["args"] = self.blockchain_delete_params() 49 | BlockChain.invoke(USERINFO_URL, data) 50 | 51 | def blockchain_delete_params(self): 52 | raise NotImplementedError("Must impl this func and return a list") 53 | 54 | pass 55 | 56 | 57 | USERINFO_INVOKE = """ 58 | { 59 | "jsonrpc": "2.0", 60 | "method": "invoke", 61 | "params": { 62 | "type": 1, 63 | "chaincodeID": { 64 | "name": "%s" 65 | }, 66 | "ctorMsg": { 67 | "function": null, 68 | "args": [ 69 | 70 | ] 71 | }, 72 | "secureContext": "user_type1_0" 73 | }, 74 | "id": 0 75 | } 76 | """ % CHAINCODE_ID 77 | USERINFO_INVOKE_DATA = json.loads(USERINFO_INVOKE) 78 | 79 | USERINFO_QUERY = """ 80 | { 81 | "jsonrpc": "2.0", 82 | "method": "query", 83 | "params": { 84 | "type": 1, 85 | "chaincodeID": { 86 | "name": "%s" 87 | }, 88 | "ctorMsg": { 89 | "function": "queryUserInfo", 90 | "args": [ 91 | 92 | ] 93 | }, 94 | "secureContext": "user_type1_0" 95 | }, 96 | "id": 0 97 | } 98 | """ % CHAINCODE_ID 99 | USERINFO_QUERY_DATA = json.loads(USERINFO_QUERY) 100 | 101 | 102 | def main(): 103 | pass 104 | 105 | 106 | if __name__ == '__main__': 107 | main() 108 | -------------------------------------------------------------------------------- /app/controllers/JobController.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | from app.modules import JobInfo, JobDetail 4 | from .UserController import get_all_agnecy, get_userindex_byuserid 5 | from app.utils import util 6 | 7 | 8 | # def get_jobindex(**argv): 9 | # return JobInfoIndex.objects.filter(**argv).first() # return None 10 | 11 | 12 | # def get_job_bcid(jobid): 13 | # return get_jobindex(JobID=jobid) 14 | 15 | 16 | # def get_tx_txid(bcid): 17 | # return get_jobindex(BCID=bcid) 18 | 19 | def get_job(**argv): 20 | return JobInfo.objects.filter(**argv).first() # return None 21 | 22 | 23 | def get_job_by_jobid(jobid): 24 | # return get_job(JobID=jobid) 25 | return get_job(id=jobid) 26 | 27 | 28 | def get_job_list(**argv): 29 | return JobInfo.objects.filter(**argv).all() # return None 30 | 31 | 32 | def get_job_list_by_order(*argv): 33 | return JobInfo.objects.order_by(*argv) 34 | 35 | 36 | def get_jobs_by_agency_userid(userid): 37 | return get_job_list(UserID=userid) 38 | 39 | 40 | def get_all_agency_and_jobs(): 41 | agnecy_list = get_all_agnecy() 42 | l = set(agnecy_list) 43 | l = sorted(l, key=lambda x: x.CurrentCreditScore, reverse=True) 44 | ret = list() 45 | # for a in agnecy_list: 46 | for a in l: 47 | # print a.UserID, a.Username 48 | jobs = get_job_list(UserID=a.UserID) 49 | agency_name = unicode(a.AgencyName) 50 | score = float(a.CurrentCreditScore) 51 | job_list = list() 52 | for j in jobs: 53 | job_list.append(j.dump_to_dict()) 54 | ret.append((agency_name, score, job_list)) 55 | return ret 56 | 57 | 58 | def get_all_jobs_by_time(max_count=20): 59 | return get_job_list_by_order("-PublishTime") 60 | 61 | 62 | def create_jobdetail(title, jobtime, place, salary, day, demand): 63 | jobdetail = JobDetail(Title=title, 64 | JobTime=jobtime, 65 | Place=place, 66 | Salary=unicode(salary), 67 | Day=unicode(day), 68 | Demand=demand) 69 | jobdetail.save() 70 | return jobdetail 71 | 72 | 73 | def create_jobinfo(userindex, title, jobtime, place, salary, day, demand): 74 | jobdetail = create_jobdetail(title, jobtime, place, salary, day, demand) 75 | job = JobInfo(AgencyName=userindex.AgencyName, 76 | UserID=userindex.UserID, 77 | JobDetail=jobdetail) 78 | job.PublishTime = util.get_time() 79 | job.save() 80 | job.bc_create() 81 | 82 | print job 83 | 84 | # to blockchain 85 | # job.bc_create() 86 | 87 | # cache 88 | # jobindex = JobInfoIndex(JobID=job.JobID, 89 | # TotalApplied=job.TotalApplied, 90 | # JobDetail=jobdetail) 91 | # jobindex.save() 92 | # 93 | # agencyindex = get_agencyindex_byid(user.UserInfo.UserID) 94 | # if agencyindex is None: 95 | # agencyindex = AgencyIndex(UserID=user.UserInfo.UserID, 96 | # AgencyName=user.UserInfo.AgencyName, 97 | # CreditScore=user.CreditScore.CurrentCreditScore) 98 | # agencyindex.JobIndexList.append(jobindex) 99 | # agencyindex.save() 100 | return job 101 | 102 | 103 | def main(): 104 | pass 105 | 106 | 107 | if __name__ == '__main__': 108 | main() 109 | -------------------------------------------------------------------------------- /app/controllers/TxController.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | from app.modules import Tx 4 | import time 5 | 6 | 7 | def get_tx(**argv): 8 | return Tx.objects.filter(**argv).first() # return None 9 | 10 | 11 | def get_tx_by_txid(txid): 12 | return get_tx(id=txid) 13 | 14 | 15 | def create_tx(userid, jobid): 16 | tx = Tx(JobID=jobid, 17 | UserID=userid, 18 | ApplyTime=unicode(int(time.time()))) 19 | tx.save() 20 | tx.bc_create() 21 | return tx 22 | 23 | 24 | def main(): 25 | pass 26 | 27 | 28 | if __name__ == '__main__': 29 | main() 30 | -------------------------------------------------------------------------------- /app/controllers/UserController.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import uuid 4 | from flask import abort 5 | from flask_wtf import Form 6 | from wtforms import StringField, PasswordField, validators 7 | from wtforms.validators import DataRequired 8 | 9 | from app.db import redisdb 10 | from app.modules import UserIndex, User, UserRole, JobInfo, Tx 11 | from app.utils import util, hashutil 12 | 13 | 14 | class LoginForm(Form): 15 | username = StringField('username', validators=[DataRequired(), validators.Length(min=3, max=20)]) 16 | password = PasswordField('password', validators=[DataRequired(), validators.Length(min=3, max=20)]) 17 | # role = RadioField('username', validators=[DataRequired(), validators.Length(min=3, max=20)]) 18 | pass 19 | 20 | 21 | # token related 22 | class RedisToken(redisdb.RedisMixIn): 23 | def __init__(self, username=None): 24 | self.username = username 25 | 26 | def stored_data(self): 27 | return {"username": self.username} 28 | 29 | pass 30 | 31 | 32 | # TODO change to expire 33 | # EXPIRE_TIME = 0 34 | EXPIRE_TIME = 60 * 30 35 | 36 | 37 | def generate_token(username): 38 | seed = username + unicode(util.get_time(True)) 39 | token = hashutil.hash_md5(seed) 40 | r_token = RedisToken(username) 41 | 42 | r_token.save_to_redis(token, expire=EXPIRE_TIME) 43 | return token 44 | 45 | 46 | def get_username_bytoken(token): 47 | return RedisToken.load_from_redis(token, EXPIRE_TIME) 48 | 49 | 50 | # query 51 | def get_userindex(**argv): 52 | return UserIndex.objects.filter(**argv).first() # return None 53 | 54 | 55 | def get_userindex_all(**argv): 56 | return UserIndex.objects.filter(**argv).all() # return None 57 | 58 | 59 | def get_userindex_byname(username): 60 | return get_userindex(Username=username) 61 | 62 | 63 | def get_userindex_byuserid(userid): 64 | return get_userindex(UserID=userid) 65 | 66 | 67 | def get_userindex_bytoken(token): 68 | data = get_username_bytoken(token) 69 | if data is not None: 70 | return get_userindex_byname(data["username"]) 71 | return None 72 | 73 | 74 | def get_all_agnecy(to_dict=False): 75 | l = get_userindex_all(Role=UserRole.Agency) 76 | if to_dict: 77 | l = [i.dump_to_dict() for i in l] 78 | return l 79 | 80 | 81 | def wrapper_userinfo(u): 82 | d = u.dump_to_dict() 83 | ids = d["Jobs"] 84 | l = list() 85 | if u.UserInfo.Role == UserRole.Student: 86 | for i in ids: 87 | tx = Tx.objects.filter(id=i).first() 88 | if tx is not None: 89 | l.append(tx.dump_to_dict()) 90 | elif u.UserInfo.Role == UserRole.Agency: 91 | for i in ids: 92 | job = JobInfo.objects.filter(id=i).first() 93 | if job is not None: 94 | l.append(job.dump_to_dict()) 95 | d["Jobs"] = l 96 | d["UserInfo"]["UserID"] = d["UserInfo"]["IDNo"] 97 | return d 98 | 99 | 100 | # create 101 | def create_userindex(username, password, role): 102 | u = UserIndex(Username=username, Password=password, Role=role) 103 | u.save() 104 | return u 105 | 106 | 107 | def update_userindex(userindex, UserID, RealName, Gender, Tele, Role, AgencyName, School, StuID): 108 | userindex.UserID = UserID 109 | userindex.RealName = RealName 110 | userindex.Gender = Gender 111 | userindex.Tele = Tele 112 | userindex.Role = Role 113 | userindex.AgencyName = AgencyName 114 | userindex.School = School 115 | userindex.StuID = StuID 116 | 117 | userindex.save() 118 | return userindex 119 | 120 | 121 | def update_userindex_role(userindex, role): 122 | userindex.Role = role 123 | userindex.save() 124 | 125 | 126 | def create_user(userindex): 127 | user = User(userindex) 128 | 129 | userindex.UserID = unicode(uuid.uuid4()) 130 | userindex.save() 131 | 132 | # create to blockchain 133 | user.bc_create() 134 | return user 135 | 136 | 137 | def update_user_balance(userid, balance): 138 | user = User.from_blockchain(userid) 139 | if user is None: 140 | abort(403, "提供的用户未在记录当中") 141 | user.Balance = balance 142 | user.bc_update() 143 | return user 144 | 145 | 146 | def update_user_current_score(userid, score): 147 | user = User.from_blockchain(userid) 148 | if user is None: 149 | abort(403, "提供的用户未在记录当中") 150 | user.CreditScore.CurrentCreditScore = score 151 | user.bc_update() 152 | user.UserInfo.CurrentCreditScore = score 153 | user.UserInfo.save() 154 | return user 155 | 156 | 157 | def main(): 158 | pass 159 | 160 | 161 | if __name__ == '__main__': 162 | main() 163 | -------------------------------------------------------------------------------- /app/controllers/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | def main(): 6 | pass 7 | 8 | 9 | if __name__ == '__main__': 10 | main() 11 | -------------------------------------------------------------------------------- /app/db/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | def main(): 6 | pass 7 | 8 | 9 | if __name__ == '__main__': 10 | main() 11 | -------------------------------------------------------------------------------- /app/db/mongodb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # from flask.ext.mongoalchemy import MongoAlchemy 4 | # from flask.ext.mongoalchemy import BaseQuery 5 | from app import app 6 | 7 | # db = MongoAlchemy(app) 8 | 9 | 10 | from mongoengine import * 11 | connect(app.config['MONGOALCHEMY_DATABASE']) 12 | 13 | # class Query(BaseQuery): 14 | # def getbykid(self, kid): 15 | # return self.filter(self.type.kid == kid) 16 | # 17 | # pass 18 | 19 | 20 | def main(): 21 | pass 22 | 23 | 24 | if __name__ == '__main__': 25 | main() 26 | -------------------------------------------------------------------------------- /app/db/redisdb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import json 5 | 6 | from app import redis_store 7 | from app.utils import util 8 | 9 | CLASS_TABLE = "class:%s:%s" 10 | CLASS_SET = "classset:%s" 11 | 12 | SEPARATOR = '_##' 13 | 14 | 15 | class RedisMixIn(object): 16 | def stored_data(self): 17 | """ 18 | 19 | :return: 20 | :rtype dict 21 | """ 22 | raise NotImplementedError("must impl!") 23 | 24 | def save_to_redis(self, key, expire=0): 25 | """ 26 | 27 | :param key: 28 | :param expire: for seconds 29 | :return: 30 | """ 31 | redis_key = CLASS_TABLE % (type(self).__name__, key) 32 | if expire != 0: 33 | redis_store.setex(redis_key, expire, json.dumps(self.stored_data())) 34 | else: 35 | redis_store.set(redis_key, json.dumps(self.stored_data())) 36 | pass 37 | 38 | @classmethod 39 | def load_from_redis(cls, key, expire=0): 40 | redis_key = CLASS_TABLE % (cls.__name__, key) 41 | ret = redis_store.get(redis_key) 42 | if ret is None: 43 | return None 44 | try: 45 | ins = json.loads(ret) 46 | if expire != 0: 47 | redis_store.expire(redis_key, expire) 48 | except Exception, e: 49 | print ("load from redis error for %s" % key) 50 | return None 51 | return ins 52 | 53 | def remove_from_redis(self, key): 54 | redis_store.delete(CLASS_TABLE % (type(self).__name__, key)) 55 | 56 | @classmethod 57 | def remove_from_redis_ex(cls, key): 58 | redis_store.delete(CLASS_TABLE % (cls.__name__, key)) 59 | 60 | @classmethod 61 | def get_count(cls): 62 | keys = redis_store.keys(CLASS_TABLE % (cls.__name__, "*")) 63 | if keys is None: 64 | return 0 65 | return len(keys) 66 | 67 | pass 68 | 69 | 70 | class RedisZSetMixIn(RedisMixIn): 71 | def add_to_set(self, score): 72 | _id = unicode(util.get_time()) 73 | return redis_store.zadd(CLASS_SET % type(self).__name__, score, SEPARATOR.join((_id, self.to_dict()))) 74 | 75 | @classmethod 76 | def get_from_set(cls, score): 77 | r = cls.get_all_from_set(score, score) # list 78 | if r: 79 | return [i[1] for i in r] # just get instances not score 80 | return r # r is [] 81 | 82 | def get_set_score(self): 83 | _id = unicode(util.get_time()) 84 | return redis_store.zscore(CLASS_SET % type(self).__name__, # key 85 | SEPARATOR.join((_id, self.to_dict()))) # item 86 | 87 | @classmethod 88 | def get_all_from_set(cls, min_score=0, max_score=-1, desc=False): 89 | if desc: 90 | ret = redis_store.zrevrange(CLASS_SET % cls.__name__, min_score, max_score, withscores=True) 91 | else: 92 | ret = redis_store.zrange(CLASS_SET % cls.__name__, min_score, max_score, withscores=True) 93 | l = list() 94 | if ret: 95 | for c, score in ret: 96 | r = c.split(SEPARATOR, 1) 97 | if len(r) == 2: 98 | try: 99 | ins = json.loads(ret) 100 | l.append((score, ins)) # (score, item) 101 | except Exception, e: 102 | print ("load from redis error for score:%s" % score) 103 | return l 104 | 105 | @classmethod 106 | def remove_all(cls): 107 | redis_store.bc_delete(CLASS_SET % cls.__name__) 108 | pass 109 | 110 | def remove_from_set(self): 111 | _id = unicode(util.get_time()) 112 | return redis_store.zrem(CLASS_SET % type(self).__name__, # key 113 | SEPARATOR.join((_id, self.to_dict()))) # item 114 | 115 | @classmethod 116 | def remove_from_set_ex(cls, score): 117 | return redis_store.zrem(CLASS_SET % cls.__name__, # key 118 | score) # score 119 | 120 | @classmethod 121 | def get_min_score_data(cls): 122 | ret = redis_store.zrangebyscore(CLASS_SET % cls.__name__, '-inf', '+inf', start=0, num=1, withscores=True) 123 | print ret 124 | if ret: 125 | print ret[0][0] 126 | r = ret[0][0].split(SEPARATOR, 1) 127 | print r 128 | if len(r) == 2: 129 | try: 130 | ins = json.loads(r[1]) 131 | return r[0][1], ins # (score, data) 132 | except Exception, e: 133 | return None 134 | 135 | return None 136 | 137 | @classmethod 138 | def get_max_score_data(cls): 139 | ret = redis_store.zrevrangebyscore(CLASS_SET % cls.__name__, '+inf', '-inf', start=0, num=1, withscores=True) 140 | print ret 141 | if ret: 142 | print ret[0][0] 143 | r = ret[0][0].split(SEPARATOR, 1) 144 | print r 145 | if len(r) == 2: 146 | try: 147 | ins = json.loads(r[1]) 148 | return ret[0][1], ins # (score, data) 149 | except Exception, e: 150 | return None 151 | return None 152 | 153 | @classmethod 154 | def set_size(cls, smin=-1, smax=-1): 155 | if smin != -1 and smax != -1 and smin <= smax: 156 | return redis_store.zcount(CLASS_SET % cls.__name__, smin, smax) 157 | return redis_store.zcard(CLASS_SET % cls.__name__) 158 | 159 | def to_dict(self): 160 | d = self.stored_data() 161 | return json.dumps(d) 162 | 163 | pass 164 | 165 | 166 | def main(): 167 | pass 168 | 169 | 170 | if __name__ == '__main__': 171 | main() 172 | -------------------------------------------------------------------------------- /app/modules/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | # !/usr/bin/env python 6 | # -*- coding: utf-8 -*- 7 | 8 | from enum import IntEnum 9 | import uuid 10 | from datetime import datetime 11 | 12 | from app.db import mongodb as db 13 | from app.utils.jsonutil import parse_json, to_json 14 | from app.blockchain.userinfo import BlockChainUserInfoMixIn 15 | from app.blockchain.tx import BlockChainTxMixIn 16 | from app.blockchain.jobinfo import BlockChainJobInfoMixIn 17 | from app.utils.util import * 18 | 19 | MAP_TO_MONGODB_DOC = False 20 | 21 | 22 | def to_int(s): 23 | try: 24 | return int(s) 25 | except ValueError: 26 | return 0 27 | 28 | 29 | def to_float(s): 30 | try: 31 | return float(s) 32 | except ValueError: 33 | return 0 34 | 35 | 36 | class BaseModule(object): 37 | @classmethod 38 | def load_from_json(cls, json_str, bcid=None): 39 | data = parse_json(json_str) 40 | if data is None: 41 | return None 42 | return cls.load_from_dict(data) 43 | 44 | @classmethod 45 | def load_from_dict(cls, data, bcid=None, **clss): 46 | c = cls() 47 | bcid = data.get("BCID") 48 | for a, b in data.iteritems(): 49 | if hasattr(c, a): 50 | if isinstance(b, dict): 51 | cls_for_dict = clss.get(a, None) 52 | if cls_for_dict is None: 53 | raise TypeError(u"一定要填写dict对应的类 for %s" % a) 54 | ins = cls_for_dict.load_from_dict(b, bcid) 55 | setattr(c, a, ins) 56 | 57 | elif isinstance(b, (list, tuple)): 58 | cls_in_list = clss.get(a, None) 59 | if cls_in_list is None: 60 | setattr(c, a, [x for x in b]) 61 | else: 62 | l = list() 63 | for x in b: 64 | if isinstance(x, dict): 65 | ins = cls_in_list.load_from_dict(x, bcid) 66 | else: 67 | raise TypeError(u"list 中如果是类那么对应的一定是dict,且这个类继承于BaseModule for %s: %s" % a, x) 68 | l.append(ins) 69 | setattr(c, a, l) 70 | else: 71 | setattr(c, a, b) 72 | 73 | return c 74 | 75 | def dump_to_json(self, to_blockchain=False): 76 | return to_json(self.dump_to_dict(to_blockchain)) 77 | 78 | def dump_to_dict(self, to_blockchain=False): 79 | # return dict(self) 80 | d = dict() 81 | for k, v in self: 82 | if isinstance(v, BaseModule): 83 | d[k] = v.dump_to_dict(to_blockchain) 84 | elif isinstance(v, (int, float)) and to_blockchain: 85 | d[k] = unicode(v) 86 | else: 87 | d[k] = v 88 | return d 89 | 90 | def __iter__(self): 91 | return self.__dict__.iteritems() 92 | 93 | 94 | class UserRole(IntEnum): 95 | Student = 0 96 | Agency = 1 97 | Admin = 2 98 | 99 | @classmethod 100 | def get(cls, num): 101 | mapping = {0: UserRole.Student, 102 | 1: UserRole.Agency, 103 | 2: UserRole.Admin} 104 | return mapping.get(num, UserRole.Student) 105 | 106 | pass 107 | 108 | 109 | UserRoleMapping = {0: "学生", 1: "兼职中介", 2: "管理员"} 110 | 111 | 112 | class UserIndex(db.Document, BaseModule): 113 | BCID = db.StringField() # blockchain id 114 | 115 | Username = db.StringField(required=True) 116 | Password = db.StringField(required=True) 117 | 118 | UserID = db.StringField(default='') 119 | IDNo = db.StringField(default='') 120 | RealName = db.StringField(default='') 121 | Gender = db.IntField(default=0) 122 | Tele = db.StringField(default='') 123 | 124 | Role = db.IntField(default=0) 125 | 126 | AgencyName = db.StringField(default='') 127 | School = db.StringField(default='') 128 | StuID = db.StringField(default='') 129 | 130 | Status = db.IntField(default=1) 131 | 132 | JobTxMap = db.MapField(field=db.StringField(), default={}) 133 | # db.ListField(db.StringField(), default=[]) 134 | CurrentCreditScore = db.IntField(default=6) # need to update 135 | TotalCreditScore = db.IntField(default=6) 136 | RateCount = db.IntField(default=1) 137 | 138 | def __hash__(self): 139 | return hash(self.UserID) 140 | 141 | def __eq__(self, other): 142 | return self.UserID 143 | 144 | @classmethod 145 | def load_from_json(cls, json_str, bcid=None): 146 | return cls.from_json(json_str) 147 | 148 | @classmethod 149 | def load_from_dict(cls, data, bcid=None, **clss): 150 | userid = data.get("UserID", None) 151 | if userid is None: 152 | u = cls() 153 | from_local = False 154 | else: 155 | u = UserIndex.objects.filter(UserID=userid).first() 156 | from_local = True 157 | if u is None: 158 | u = cls() 159 | from_local = False 160 | # u = UserIndex() 161 | if bcid is not None: 162 | u.BCID = bcid 163 | if not from_local: 164 | u.Username = data.get("Username", "") 165 | u.Password = data.get("Password", "") 166 | 167 | u.UserID = data.get("UserID", "") 168 | u.RealName = data.get("RealName", "") 169 | u.Gender = to_int(data.get("Gender", 0)) 170 | u.Tele = data.get("Tele", "") 171 | 172 | u.Role = to_int(data.get("Role", 0)) 173 | 174 | u.AgencyName = data.get("AgencyName", "") 175 | u.School = data.get("School", "") 176 | u.StuID = data.get("StuID", "") 177 | 178 | u.Status = to_int(data.get("Status", 1)) 179 | u.save() 180 | return u 181 | 182 | def dump_to_dict(self, to_blockchain=False): 183 | d = self.to_mongo() 184 | d.pop("_id", None) # _id belong to mongodb 185 | d.pop("BCID", None) 186 | d.pop("Jobs", None) 187 | d.pop("JobTxMap", None) 188 | if to_blockchain: 189 | d.pop("CurrentCreditScore", None) 190 | d.pop("TotalCreditScore", None) 191 | d.pop("RateCount", None) 192 | d.pop("IDNo", None) 193 | for k, v in d.iteritems(): 194 | d[k] = unicode(v) 195 | else: 196 | d["Score"] = d["CurrentCreditScore"] 197 | d.pop("Password", None) 198 | return d 199 | 200 | 201 | class JobDetail(db.Document, BaseModule): 202 | # def __init__(self, jobtime="", place="", salary="", day="", demand=""): 203 | # self.JobTime = jobtime 204 | # self.Place = place 205 | # self.Salary = salary 206 | # self.Day = day 207 | # self.Demand = demand 208 | Title = db.StringField(default='') 209 | JobTime = db.StringField() 210 | Place = db.StringField() 211 | Salary = db.StringField() 212 | Day = db.StringField() 213 | Demand = db.StringField() 214 | 215 | @classmethod 216 | def load_from_json(cls, json_str, bcid=None): 217 | return cls.from_json(json_str) 218 | 219 | @classmethod 220 | def load_from_dict(cls, data, bcid=None, **clss): 221 | jobdetail = cls() 222 | jobdetail.Title = data.get("Title", "") 223 | jobdetail.JobTime = data.get("JobTime", "") 224 | jobdetail.Place = data.get("Place", "") 225 | jobdetail.Salary = data.get("Salary", "") 226 | jobdetail.Day = data.get("Day", "") 227 | jobdetail.Demand = data.get("Demand", "") 228 | return jobdetail 229 | 230 | def dump_to_dict(self, to_blockchain=False): 231 | d = self.to_mongo() 232 | d.pop("_id", None) # _id belong to mongodb 233 | d.pop("BCID", None) 234 | # if to_blockchain: 235 | # # TODO jump title 236 | # d.pop("Title", None) 237 | if to_blockchain: 238 | for k, v in d.iteritems(): 239 | d[k] = unicode(v) 240 | return d 241 | 242 | 243 | class CreditScore(BaseModule): 244 | def __init__(self, cur_credit=6, total_credit=6, rate_times=1): 245 | self.CurrentCreditScore = cur_credit 246 | self.TotalCreditScore = total_credit 247 | self.Ratetimes = rate_times 248 | pass 249 | 250 | @classmethod 251 | def load_from_dict(cls, data, bcid=None, **clss): 252 | ins = cls() 253 | ins.CurrentCreditScore = to_int(data.get("CurrentCreditScore", 6)) 254 | ins.TotalCreditScore = to_int(data.get("TotalCreditScore", 6)) 255 | ins.Ratetimes = to_int(data.get("Ratetimes", 1)) 256 | return ins 257 | 258 | def dump_to_dict(self, to_blockchain=False): 259 | d = super(CreditScore, self).dump_to_dict(to_blockchain) 260 | if not to_blockchain: 261 | d["RateCount"] = d["Ratetimes"] 262 | return d 263 | 264 | def __str__(self): 265 | return "CurrentCreditScore: %s, TotalCreditScore: %s, Ratetimes: %s" % \ 266 | (self.CurrentCreditScore, self.TotalCreditScore, self.Ratetimes) 267 | 268 | pass 269 | 270 | 271 | class User(BaseModule, BlockChainUserInfoMixIn): 272 | def __init__(self, userindex=None, creditscore=None, balance=10000, jobs=None): 273 | if userindex is None: 274 | userindex = UserIndex() 275 | self.UserInfo = userindex 276 | if creditscore is None: 277 | creditscore = CreditScore() 278 | self.CreditScore = creditscore 279 | self.Balance = balance 280 | if jobs is None: 281 | jobs = list() 282 | self.Jobs = jobs 283 | 284 | @classmethod 285 | def load_from_json(cls, json_str, bcid=None): 286 | data = parse_json(json_str) 287 | if data is None: 288 | return None 289 | userinfo = UserIndex.load_from_dict(data["UserInfo"], bcid) 290 | return User(userindex=userinfo, 291 | creditscore=data["CreditScore"], 292 | balance=data["Balance"], 293 | jobs=data["Jobs"]) 294 | 295 | @classmethod 296 | def load_from_dict(cls, data, bcid=None, **clss): 297 | ins = super(User, cls).load_from_dict(data, bcid, UserInfo=UserIndex, CreditScore=CreditScore) 298 | ins.Balance = to_int(ins.Balance) 299 | return ins 300 | 301 | # TODO dumptodict balance 302 | 303 | # blockchain related 304 | def blockchain_create_params(self): 305 | return [self.UserInfo.UserID, self.dump_to_json(True)] 306 | 307 | def blockchain_delete_params(self): 308 | return [self.UserInfo.UserID] 309 | 310 | def blockchain_update_params(self): 311 | return [self.UserInfo.UserID, self.dump_to_json(True)] 312 | 313 | 314 | class Tx(db.Document, BaseModule, BlockChainTxMixIn): 315 | JobID = db.StringField() 316 | UserID = db.StringField() 317 | ApplyTime = db.StringField() 318 | # State = db.IntField(default=0) 319 | Status = db.StringField(default='') 320 | StuScore = db.IntField(default=0) 321 | AgencyScore = db.IntField(default=0) 322 | 323 | def blockchain_create_params(self): 324 | # return [self.TxID, self.dump_to_json()] 325 | return [unicode(self.id), self.dump_to_json(True)] 326 | 327 | def blockchain_check_params(self, result): 328 | return [unicode(self.id), unicode(result)] 329 | 330 | def blockchain_evaluate_params(self, userid, score): 331 | return [unicode(self.id), userid, unicode(score)] 332 | 333 | @classmethod 334 | def load_from_json(cls, json_str, bcid=None): 335 | return cls.from_json(json_str) 336 | 337 | @classmethod 338 | def load_from_dict(cls, data, bcid=None, **clss): 339 | txid = data.get("TxID", None) 340 | if txid is None: 341 | tx = cls() 342 | else: 343 | tx = Tx.objects.filter(id=txid).first() 344 | if tx is None: 345 | tx = cls() 346 | 347 | tx.JobID = data.get("JobID", "") 348 | tx.UserID = data.get("UserID", "") 349 | tx.ApplyTime = data.get("ApplyTime", "") 350 | tx.Status = data.get("Status", '') 351 | tx.StuScore = to_int(data.get("StuScore", 0)) 352 | tx.AgencyScore = to_int(data.get("AgencyScore", 0)) 353 | 354 | tx.save() 355 | return tx 356 | 357 | def dump_to_dict(self, to_blockchain=False): 358 | d = self.to_mongo().to_dict() 359 | if to_blockchain: 360 | if d["StuScore"] == 0: 361 | d["StuScore"] = '' 362 | if d["AgencyScore"] == 0: 363 | d["AgencyScore"] = '' 364 | else: 365 | d["State"] = get_status(d["Status"]) 366 | student = UserIndex.objects.filter(UserID=d.get("UserID", '')).first() 367 | if student is not None: 368 | d["UserInfo"] = student.dump_to_dict() 369 | t = int(d["ApplyTime"]) 370 | d["Time"] = t 371 | d["ApplyTime"] = datetime.fromtimestamp(t).strftime('%Y-%m-%d %H:%M') 372 | 373 | if "_id" not in d: 374 | raise Exception("Tx doesn't has id field!") 375 | 376 | d["TxID"] = unicode(d.pop("_id")) 377 | if to_blockchain: 378 | for k, v in d.iteritems(): 379 | d[k] = unicode(v) 380 | return d 381 | 382 | 383 | STATUS_MAP = {u"未通过": 0, 384 | u"已通过": 1, 385 | u"已评价": 2, 386 | u"已结算": 3, 387 | u"中介审核": 4} 388 | 389 | 390 | def get_status(s): 391 | if s == '': 392 | return 0 393 | for k in STATUS_MAP.iterkeys(): 394 | if s.find(k) != -1: 395 | return STATUS_MAP[k] 396 | return 0 397 | 398 | 399 | class JobInfo(db.Document, BaseModule, BlockChainJobInfoMixIn): 400 | # def __init__(self, jobid=None, agency="", userid="", jobdetail=None, txs=None, 401 | # totalapplied=0, waitcheck=0, hired=0, settled=0): 402 | # """ 403 | # 404 | # :param jobid: 405 | # :type jobid str | None 406 | # :param username: 407 | # :type username str 408 | # :param userid: 409 | # :type userid str 410 | # :param jobdetail: 411 | # :type jobdetail str 412 | # :param txs: 413 | # :type txs list 414 | # :param totalapplied: 415 | # :type totalapplied int 416 | # :param waitcheck: 417 | # :type waitcheck int 418 | # :param hired: 419 | # :type hired int 420 | # :param settled: 421 | # :type settled int 422 | # """ 423 | # self.AgencyName = agency 424 | # self.UserID = userid 425 | # if jobdetail is None: 426 | # jobdetail = JobDetail("", "", 0, 0, "") 427 | # self.JobDetail = jobdetail 428 | # if txs is None: 429 | # txs = list() 430 | # self.Txs = txs 431 | # self.TotalApplied = totalapplied 432 | # self.TotalWaitCheck = waitcheck 433 | # self.TotalHired = hired 434 | # self.TotalSettled = settled 435 | # if not jobid: # jobid is 0, "", None 436 | # jobid = str(uuid.uuid4()) 437 | # self.JobID = jobid 438 | 439 | AgencyName = db.StringField() 440 | UserID = db.StringField() 441 | JobDetail = db.ReferenceField(JobDetail) 442 | Txs = db.ListField(db.ReferenceField(Tx)) 443 | TotalApplied = db.IntField(default=0) 444 | TotalWaitCheck = db.IntField(default=0) 445 | TotalHired = db.IntField(default=0) 446 | TotalSettled = db.IntField(default=0) 447 | PublishTime = db.IntField(default=0) 448 | 449 | @classmethod 450 | def load_from_dict(cls, data, bcid=None, **clss): 451 | return super(JobInfo, cls).load_from_dict(data, bcid, JobDetail=JobDetail) 452 | 453 | def blockchain_jobrelated_params(self): 454 | # return [self.JobID] 455 | return [unicode(self.id)] 456 | 457 | def blockchain_create_params(self): 458 | # return [self.JobID, self.dump_to_json()] 459 | return [unicode(self.id), self.dump_to_json(True)] 460 | 461 | def blockchain_update_params(self): 462 | # return [self.JobID, self.dump_to_json()] 463 | return [unicode(self.id), self.dump_to_json(True)] 464 | 465 | def blockchain_delete_params(self): 466 | # return [self.JobID] 467 | return [unicode(self.id)] 468 | 469 | def blockchain_addtx_params(self, txid): 470 | # return [self.JobID, txid] 471 | return [unicode(self.id), unicode(txid)] 472 | 473 | @classmethod 474 | def load_from_json(cls, json_str, bcid=None): 475 | return cls.from_json(json_str) 476 | 477 | @classmethod 478 | def load_from_dict(cls, data, bcid=None, **clss): 479 | jobid = data.get("JobID", None) 480 | if jobid is None: 481 | jobinfo = cls() 482 | from_source = False 483 | else: 484 | jobinfo = JobInfo.objects.filter(id=jobid).first() 485 | from_source = True 486 | if jobinfo is None: 487 | jobinfo = cls() 488 | from_source = True 489 | if from_source: 490 | jobdetail_data = data.get("JobDetail", {}) 491 | jobinfo.JobDetail.JobTime = jobdetail_data.get("JobTime", "") 492 | jobinfo.JobDetail.Place = jobdetail_data.get("Place", "") 493 | jobinfo.JobDetail.Salary = jobdetail_data.get("Salary", "") 494 | jobinfo.JobDetail.Day = jobdetail_data.get("Day", "") 495 | jobinfo.JobDetail.Demand = jobdetail_data.get("Demand", "") 496 | jobinfo.JobDetail.save() 497 | else: 498 | jobdetail = JobDetail.load_from_dict(data.get("JobDetail", {})) # data.get("AgencyName", "") 499 | jobdetail.save() 500 | jobinfo.JobDetail = jobdetail 501 | 502 | jobinfo.Txs = [] 503 | for t in data.get("Txs", []): 504 | if len(t) == 24: 505 | print t 506 | tx = Tx.objects.filter(id=t).first() 507 | if tx is not None: 508 | jobinfo.Txs.append(tx) 509 | 510 | jobinfo.AgencyName = data.get("AgencyName", "") 511 | jobinfo.UserID = data.get("UserID", "") 512 | 513 | jobinfo.TotalApplied = to_int(data.get("TotalApplied", 0)) 514 | jobinfo.TotalWaitCheck = to_int(data.get("TotalWaitCheck", 0)) 515 | jobinfo.TotalHired = to_int(data.get("TotalHired", 0)) 516 | jobinfo.TotalSettled = to_int(data.get("TotalSettled", 0)) 517 | 518 | jobinfo.save() 519 | 520 | return jobinfo 521 | 522 | def dump_to_dict(self, to_blockchain=False): 523 | d = self.to_mongo().to_dict() 524 | print d 525 | if "_id" not in d: 526 | raise Exception("JobInfo doesn't has id field!") 527 | d["JobID"] = unicode(d.pop("_id")) 528 | d.pop("CreditScore", None) 529 | d.pop("BCID", None) 530 | if to_blockchain: 531 | d["Txs"] = [unicode(i.id) for i in self.Txs] 532 | d.pop("PublishTime", None) 533 | else: 534 | d["Txs"] = [i.dump_to_dict(to_blockchain) for i in self.Txs] 535 | d["Time"] = d["PublishTime"] 536 | d["PublishTime"] = datetime.fromtimestamp(d["PublishTime"]).strftime('%Y-%m-%d %H:%M') 537 | d["JobDetail"] = self.JobDetail.dump_to_dict(to_blockchain) 538 | if to_blockchain: 539 | d["TotalApplied"] = unicode(d["TotalApplied"]) 540 | d["TotalWaitCheck"] = unicode(d["TotalWaitCheck"]) 541 | d["TotalHired"] = unicode(d["TotalHired"]) 542 | d["TotalSettled"] = unicode(d["TotalSettled"]) 543 | return d 544 | 545 | 546 | def main(): 547 | pass 548 | 549 | 550 | if __name__ == '__main__': 551 | main() 552 | -------------------------------------------------------------------------------- /app/routersjobs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | from . import app 4 | from .routersutil import * 5 | from app.modules import JobInfo, UserRole, User 6 | from app.controllers import JobController, UserController 7 | 8 | 9 | @app.route('/job/all', methods=['GET', 'POST']) 10 | @allow_cross_domain 11 | def get_all_jobs(): 12 | l = JobController.get_all_agency_and_jobs() 13 | ret = list() 14 | for i in l: # i is agencyindex 15 | count = 0 16 | name = unicode(i[0]) 17 | score = float(i[1]) 18 | for job in reversed(i[2]): 19 | if count > 5: 20 | break 21 | ret.append({"AgencyName": name, "Score": score, "JobInfo": job}) 22 | count += 1 23 | return return_data(data=ret) 24 | 25 | 26 | @app.route('/job/time/all', methods=['GET', 'POST']) 27 | @allow_cross_domain 28 | def get_all_jobs_by_time(): 29 | jobs = JobController.get_all_jobs_by_time() 30 | ret = list() 31 | max_count = 20 32 | max_count = max_count if max_count < len(jobs) else len(jobs) 33 | for i in range(max_count): 34 | job = jobs[i] 35 | print job.PublishTime 36 | userindex = UserController.get_userindex_byuserid(job.UserID) 37 | if userindex is not None: 38 | ret.append({"AgencyName": userindex.AgencyName, "Score": userindex.CurrentCreditScore, 39 | "JobInfo": job.dump_to_dict()}) 40 | 41 | return return_data(data=ret) 42 | 43 | 44 | @app.route('/job/agency/publish', methods=['GET', 'POST']) 45 | @allow_cross_domain 46 | @check_auth_ext 47 | def publish_job(userindex): 48 | if userindex.Role != UserRole.Agency: 49 | abort(403, u"只有中介能发布信息") 50 | data = get_data_from_ajax() 51 | 52 | check_list = list() 53 | title = data.get("Title", None) 54 | jobtime = data.get("JobTime", None) 55 | place = data.get("Place", None) 56 | salary = data.get("Salary", None) 57 | day = data.get("Day", None) 58 | demand = data.get("Demand", None) 59 | 60 | check_list.append(title) 61 | check_list.append(jobtime) 62 | check_list.append(place) 63 | check_list.append(salary) 64 | check_list.append(day) 65 | check_list.append(demand) 66 | 67 | if check_list.count(None): 68 | abort(400, u"缺少参数%d" % check_list.index(None)) 69 | 70 | try: 71 | s = int(salary) 72 | if s <= 0 or s > 65535: 73 | abort(400, u"Salary 设置不合理") 74 | except ValueError, e: 75 | abort(400, u"Salary 必须是一个整数") 76 | 77 | job = JobController.create_jobinfo(userindex, title, jobtime, place, salary, day, demand) 78 | userindex.JobTxMap[unicode(job.id)] = "" 79 | userindex.save() 80 | return return_data(data=job.dump_to_dict()) 81 | 82 | 83 | @app.route('/job/agency/jobs', methods=['GET', 'POST']) 84 | @allow_cross_domain 85 | @check_auth 86 | def get_agency_jobs(userindex): 87 | """ 88 | from cache 89 | :param userindex: 90 | :return: 91 | """ 92 | data = get_data_from_ajax() 93 | if userindex.Role != UserRole.Agency: 94 | abort(403, u"只有中介可以查询") 95 | l = list() 96 | 97 | state = data.get("State", None) 98 | if state is not None: 99 | try: 100 | state = int(state) 101 | if not (0 <= state <= 4): 102 | abort(400, "State 只能是 0,1,2,3,4") 103 | except ValueError, e: 104 | abort(400, "State 只能是数字") 105 | 106 | for jobid in userindex.JobTxMap.keys(): 107 | job = JobController.get_job_by_jobid(jobid) 108 | if job is not None: 109 | d = job.dump_to_dict() 110 | if state is not None: 111 | tx_list = list() 112 | txs = d["Txs"] 113 | for t in txs: 114 | if t['State'] == state: 115 | tx_list.append(t) 116 | tx_list.sort(key=lambda x: x["Time"], reverse=True) 117 | d["Txs"] = tx_list 118 | 119 | l.append(d) 120 | l.sort(key=lambda x: x["Time"], reverse=True) 121 | return return_data(data=l) 122 | 123 | 124 | @app.route('/job/query', methods=['GET', 'POST']) 125 | @allow_cross_domain 126 | def job_query(): 127 | data = get_data_from_ajax() 128 | jobid = data.get("JobID", None) 129 | if jobid is None: 130 | abort(400, "缺少 JobID") 131 | 132 | job = JobInfo.from_blockchain(jobid) 133 | if job is None: 134 | abort(403, u"没有查找到对应JobID: %s 的兼职信息" % jobid) 135 | # print type(job.id) 136 | job.save() 137 | 138 | d = job.dump_to_dict() 139 | username = data.get("username", None) 140 | if username is None: 141 | username = data.get("Username", None) 142 | if username is not None: 143 | userindex = UserController.get_userindex_byname(username) 144 | if userindex is not None: 145 | if jobid in userindex.JobTxMap.keys(): 146 | d["IsApplied"] = True 147 | else: 148 | d["IsApplied"] = False 149 | 150 | state = data.get("State", None) 151 | if state is not None: 152 | try: 153 | state = int(state) 154 | if not (0 <= state <= 4): 155 | abort(400, "State 只能是 0,1,2,3,4") 156 | except ValueError, e: 157 | abort(400, "State 只能是数字") 158 | txs = d["Txs"] 159 | l = list() 160 | for t in txs: 161 | if t['State'] == state: 162 | l.append(t) 163 | d["Txs"] = l 164 | 165 | return return_data(data=d) 166 | 167 | 168 | ############################ 169 | @app.route('/job/loadbctest', methods=['GET', 'POST']) 170 | def load_bc_test(): 171 | job = JobInfo.from_blockchain('590e9e4ee588d600d4fb0aaf') 172 | # print type(job.id) 173 | return return_data(data=job.dump_to_dict()) 174 | 175 | 176 | @app.route('/job/loadtest', methods=['GET', 'POST']) 177 | def loadtest_job(): 178 | s = """{ 179 | "JobDetail": { 180 | "Day": 0, 181 | "Demand": "", 182 | "JobTime": "", 183 | "Place": "", 184 | "Salary": 0 185 | }, 186 | "JobID": "085308f0-38f8-40a3-b631-7cb33811a985", 187 | "TotalApplied": "123", 188 | "TotalHired": "123", 189 | "TotalSettled": "123", 190 | "TotalWaitCheck": "123", 191 | "Txs": [ 192 | "123", 193 | "123" 194 | ] 195 | }""" 196 | data = json.loads(s) 197 | ins = JobInfo.load_from_dict(data) 198 | return return_data(data=ins.dump_to_dict()) 199 | 200 | # def main(): 201 | # pass 202 | # 203 | # 204 | # if __name__ == '__main__': 205 | # main() 206 | -------------------------------------------------------------------------------- /app/routerstxs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | from . import app 4 | from .routersutil import * 5 | from app.modules import Tx, UserRole 6 | from app.controllers import TxController, JobController 7 | 8 | 9 | @app.route('/tx/apply', methods=['GET', 'POST']) 10 | @allow_cross_domain 11 | @check_auth_ext 12 | def student_apply(userindex): 13 | data = get_data_from_ajax() 14 | JobID = data.get("JobID", None) 15 | if JobID is None: 16 | abort(400, u"缺少 JobID") 17 | 18 | if JobID in userindex.JobTxMap.keys(): 19 | tx = Tx.from_blockchain(unicode(userindex.JobTxMap[JobID])) 20 | if tx is not None: 21 | tx.save() 22 | print "tx from existed data!" 23 | return return_data(data=tx.dump_to_dict()) 24 | 25 | tx = TxController.create_tx(userindex.UserID, JobID) 26 | # add tx status re-get 27 | new_tx = Tx.from_blockchain(unicode(tx.id)) 28 | if new_tx is None: 29 | abort(403, u"创建 %s 没有成功" % tx.id) 30 | new_tx.save() 31 | 32 | job = JobController.get_job_by_jobid(jobid=JobID) 33 | if job is not None: 34 | job.TotalApplied += 1 35 | job.save() 36 | userindex.JobTxMap[JobID] = unicode(new_tx.id) # {jobid: txid} 37 | userindex.save() 38 | 39 | return return_data(data=new_tx.dump_to_dict()) 40 | 41 | 42 | @app.route('/tx/student/jobs', methods=['GET', 'POST']) 43 | @allow_cross_domain 44 | @check_auth_ext 45 | def get_student_txs(userindex): 46 | if userindex.Role != UserRole.Student: 47 | abort(403, u"只有学生可以查询") 48 | l = list() 49 | for jobid, txid in userindex.JobTxMap.items(): 50 | job = JobController.get_job_by_jobid(jobid) 51 | # TODO check with front end 52 | if job is not None: 53 | d = job.dump_to_dict() 54 | # TODO wait for check 55 | txs = d.pop("Txs") 56 | d["Tx"] = TxController.get_tx_by_txid(txid).dump_to_dict() 57 | l.append(d) 58 | l.sort(key=lambda x: x["Tx"]["Time"], reverse=True) 59 | 60 | data = get_data_from_ajax() 61 | state = data.get("State", None) 62 | if state is not None: 63 | try: 64 | state = int(state) 65 | if not (0 <= state <= 4): 66 | abort(400, "State 只能是 0,1,2,3,4") 67 | except ValueError, e: 68 | abort(400, "State 只能是数字") 69 | ret = list() 70 | for t in l: 71 | if t["Tx"]['State'] == state: 72 | ret.append(t) 73 | return return_data(data=ret) 74 | return return_data(data=l) 75 | 76 | 77 | @app.route('/tx/query', methods=['GET', 'POST']) 78 | @allow_cross_domain 79 | def tx_query(): 80 | data = get_data_from_ajax() 81 | txid = data.get("TxID", None) 82 | if txid is None: 83 | abort(400, u"缺少 TxID") 84 | 85 | tx = Tx.from_blockchain(txid) 86 | if tx is None: 87 | abort(403, u"没有查找到对应JobID: %s 的兼职信息" % txid) 88 | tx.save() 89 | return return_data(data=tx.dump_to_dict()) 90 | 91 | 92 | @app.route('/tx/agency/check', methods=['GET', 'POST']) 93 | @allow_cross_domain 94 | @check_auth 95 | def agency_check(userindex): 96 | if userindex.Role != UserRole.Agency: 97 | abort(403, u"只有中介可以检查") 98 | data = get_data_from_ajax() 99 | txid = data.get("TxID", None) 100 | result = data.get("Result", None) 101 | if txid is None or result is None: 102 | abort(400, u"缺少 TxID 或 Result") 103 | # tx = Tx.from_blockchain(txid) 104 | tx = TxController.get_tx_by_txid(txid) 105 | if tx is None: 106 | abort(403, u"提供的tx: %s 不存在" % txid) 107 | 108 | result = unicode(result) 109 | if result not in [u"1", u"2"]: 110 | abort(403, u"result only can be: 1 or 2") 111 | tx.bc_artificial_check(result) 112 | # lookup 113 | tx = Tx.from_blockchain(txid) 114 | tx.save() 115 | return return_data(data=tx.dump_to_dict()) 116 | 117 | 118 | @app.route('/tx/evaluate', methods=['GET', 'POST']) 119 | @allow_cross_domain 120 | @check_auth_ext 121 | def evaluate(userindex): 122 | data = get_data_from_ajax() 123 | txid = data.get("TxID", None) 124 | score = data.get("Score", None) 125 | if txid is None or score is None: 126 | abort(400, u"缺少 TxID 或 Score") 127 | 128 | try: 129 | score = int(score) 130 | if score < 0 or score > 10: 131 | abort(400, u"评分必须在0-10之间") 132 | except ValueError, e: 133 | abort(400, u"评分必须是0-10中的一个数字") 134 | 135 | userid = userindex.UserID 136 | # tx = Tx.from_blockchain(txid) 137 | tx = TxController.get_tx_by_txid(txid) 138 | if tx is None: 139 | abort(403, u"提供的tx: %s 不存在" % txid) 140 | 141 | tx.bc_evaluate(userid, score) 142 | # return tx state 143 | # lookup 144 | tx = Tx.from_blockchain(txid) 145 | tx.save() 146 | return return_data(data=tx.dump_to_dict()) 147 | -------------------------------------------------------------------------------- /app/routersuser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | from flask import request, flash, redirect, url_for, session 4 | from . import app 5 | from .routersutil import * 6 | 7 | from app.controllers import UserController, JobController 8 | from app.modules import UserIndex, User, UserRole, UserRoleMapping 9 | from app.utils import hashutil 10 | 11 | 12 | # user 13 | @app.route('/user/login', methods=['GET', 'POST']) 14 | @allow_cross_domain 15 | def login(): 16 | form = UserController.LoginForm(request.form) 17 | msg = '' 18 | role = UserRole.Student 19 | if request.method == 'POST': 20 | ajax = False 21 | if request_wants_json(): 22 | ajax = True 23 | data = get_data_from_ajax() 24 | form.username.data = unicode(data.get('username', None)) 25 | form.password.data = unicode(data.get('password', None)) 26 | role = data.get('role', None) 27 | role = int(role) if role is not None else UserRole.Student 28 | if ajax or form.validate_on_submit(): 29 | username = form.username.data 30 | password = hashutil.hash_md5(form.password.data) 31 | userindex = UserController.get_userindex_byname(username) 32 | role = UserRole.get(role) 33 | if userindex is None: 34 | # userindex = UserController.create_userindex(username, password, role) 35 | # token = UserController.generate_token(username) 36 | # return return_data(None, {'token': token, 'detail': False}, 37 | # msg="register success for %s" % userindex.Username) 38 | abort(403, "该用户不存在,请先注册!") 39 | else: 40 | if password == userindex.Password: 41 | if role != userindex.Role: 42 | abort(403, u"该用户登陆时选择了不同的身份(应该为:%s)" % UserRoleMapping.get(userindex.Role, u"学生")) 43 | 44 | # enter index page 45 | # session['user'] = userindex.username 46 | msg = 'You were successfully login in for user:%s !' % username 47 | flash(msg) 48 | # if request_wants_json(): 49 | # return jsonify(jsonutil.json_wrapper({}, 0, msg)) 50 | token = UserController.generate_token(username) 51 | 52 | detail = False if userindex.UserID == '' else True 53 | return return_data(None, {'token': token, 'detail': detail}, 54 | msg="login success for %s" % userindex.Username) 55 | else: 56 | msg = u"密码错误!" 57 | flash(msg) 58 | pass 59 | else: 60 | msg = u'用户名或者密码不符合要求(最小3位最长20位)' 61 | flash(msg) 62 | else: 63 | msg = u'请登陆' 64 | flash(msg) 65 | 66 | if request_wants_json(): 67 | abort(401, msg) 68 | 69 | return render_template('login.html', form=form, info=msg) 70 | 71 | 72 | @app.route('/user/register', methods=['GET', 'POST']) 73 | @allow_cross_domain 74 | def register(): 75 | data = get_data_from_ajax() 76 | username = data.get('username', None) 77 | password = data.get('password', None) 78 | role = data.get('role', None) 79 | if username is None or password is None or role is None: 80 | abort(400, u"必须填写username和password和role") 81 | 82 | username = unicode(username) 83 | userindex = UserController.get_userindex_byname(username) 84 | if userindex is not None: 85 | abort(403, u"该用户(%s)已经注册过" % username) 86 | 87 | password = hashutil.hash_md5(unicode(password)) 88 | try: 89 | role = int(role) if role is not None else UserRole.Student 90 | except ValueError, e: 91 | abort(403, u"Role 必须为整数") 92 | 93 | if role not in [0, 1]: 94 | abort(403, u"Role 必须为 0 或 1") 95 | 96 | userindex = UserController.create_userindex(username, password, role) 97 | token = UserController.generate_token(username) 98 | return return_data(None, {'token': token, 'detail': False}, 99 | msg="register success for %s" % userindex.Username) 100 | 101 | 102 | @app.route('/user/detail', methods=['GET', 'POST']) 103 | @allow_cross_domain 104 | @check_auth 105 | def finish_userdetail_info(userindex): 106 | data = get_data_from_ajax() 107 | userid = data.get("UserID", None) 108 | if userid is None: 109 | userid = data.get("IDNo", None) 110 | realname = data.get("RealName", None) 111 | gender = data.get("Gender", None) 112 | tele = data.get("Tele", None) 113 | 114 | userindex.IDNo = userid 115 | userindex.RealName = realname 116 | userindex.Gender = gender 117 | userindex.Tele = tele 118 | check_list = list() 119 | check_list.append(userid) 120 | check_list.append(realname) 121 | if userindex.Role == UserRole.Student: 122 | school = data.get("School") 123 | stuid = data.get("StuID") 124 | userindex.School = school 125 | userindex.StuID = stuid 126 | check_list.append(school) 127 | check_list.append(stuid) 128 | 129 | if check_list.count(None): 130 | abort(400, u"缺少完整参数: %d" % check_list.index(None)) 131 | userindex.School = school 132 | userindex.StuID = stuid 133 | elif userindex.Role == UserRole.Agency: 134 | agencyname = data.get("AgencyName") 135 | check_list.append(agencyname) 136 | if check_list.count(None): 137 | abort(400, u"缺少完整参数: %d" % check_list.index(None)) 138 | userindex.AgencyName = agencyname 139 | else: 140 | abort(400, "role error!") 141 | 142 | user = UserController.create_user(userindex) 143 | return return_data(None, data=user.dump_to_dict()) 144 | 145 | 146 | # @app.route('/user/modify', methods=['GET', 'POST']) 147 | # @allow_cross_domain 148 | # @check_auth 149 | # def modify_userinfo(userindex): 150 | # data = get_data_from_ajax() 151 | # for k, v in data.iteritems(): 152 | # if hasattr(userindex, k): 153 | # setattr(userindex, k, v) 154 | # 155 | # UserController.update_userinfo(userindex) 156 | # return return_data(None, data=userindex.dump_to_dict()) 157 | 158 | 159 | @app.route('/user/info', methods=['GET', 'POST']) 160 | @allow_cross_domain 161 | @check_auth_ext 162 | def userinfo(userindex): 163 | # data = get_data_from_ajax() 164 | # if data is None: 165 | # return 166 | u = User.from_blockchain(userindex.UserID) 167 | if u is None: 168 | abort(403, u"用户不存在于区块链记录中或访问区块链失败") 169 | u.UserInfo.CurrentCreditScore = u.CreditScore.CurrentCreditScore 170 | u.UserInfo.TotalCreditScore = u.CreditScore.TotalCreditScore 171 | u.UserInfo.RateCount = u.CreditScore.Ratetimes 172 | u.UserInfo.save() 173 | d = UserController.wrapper_userinfo(u) 174 | 175 | # return return_data(None, data=u.dump_to_dict()) 176 | return return_data(None, data=d) 177 | 178 | 179 | @app.route('/user/score', methods=['GET', 'POST']) 180 | @allow_cross_domain 181 | @check_auth_ext 182 | def userinfo_score(userindex): 183 | return return_data(None, data={ 184 | "CurrentCreditScore": userindex.CurrentCreditScore, 185 | "TotalCreditScore": userindex.TotalCreditScore, 186 | "RateCount": userindex.RateCount, 187 | }) 188 | 189 | 190 | @app.route('/user/allagency', methods=['GET', 'POST']) 191 | @allow_cross_domain 192 | def get_all_agency(): 193 | data = UserController.get_all_agnecy(True) 194 | print data 195 | return return_data(None, data=data) 196 | 197 | 198 | @app.route('/user/agency', methods=['GET', 'POST']) 199 | @allow_cross_domain 200 | def user_agency(): 201 | data = get_data_from_ajax() 202 | jobid = data.get("JobID", None) 203 | if jobid is None: 204 | abort(400, "缺少 JobID") 205 | 206 | jobinfo = JobController.get_job_by_jobid(jobid) 207 | if jobinfo is None: 208 | abort(403, "查询的 JobID: %s 不存在" % jobid) 209 | 210 | userindex = UserController.get_userindex_byuserid(jobinfo.UserID) 211 | d = userindex.dump_to_dict() 212 | d["Score"] = userindex.CurrentCreditScore 213 | d["JobsCount"] = len(userindex.JobTxMap) 214 | return return_data(None, data=d) 215 | 216 | 217 | @app.route('/user/update/balance', methods=['GET', 'POST']) 218 | @allow_cross_domain 219 | @check_auth_ext 220 | def update_balance(userindex): 221 | data = get_data_from_ajax() 222 | balance = data.get("Balance", None) 223 | if balance is None: 224 | abort(400, u"缺少参数Balance") 225 | 226 | user = UserController.update_user_balance(userindex.UserID, balance) 227 | return return_data(None, data=user.dump_to_dict()) 228 | 229 | 230 | @app.route('/user/update/score', methods=['GET', 'POST']) 231 | @allow_cross_domain 232 | @check_auth_ext 233 | def update_score(userindex): 234 | data = get_data_from_ajax() 235 | score = data.get("Score", None) 236 | if score is None: 237 | abort(400, u"缺少参数Score") 238 | 239 | try: 240 | score = int(score) 241 | except ValueError: 242 | score = -1 243 | 244 | if not (0 <= score <= 10): 245 | abort(403, u"Score 必须在 0 \ 17 | # request.accept_mimetypes['text/html'] 18 | 19 | 20 | def return_data(html=None, data=None, code=0, msg=''): 21 | if data is None: 22 | data = dict() 23 | if html is None or request_wants_json(): 24 | return jsonify(jsonutil.json_wrapper(data, code, msg)) 25 | if not isinstance(data, dict): 26 | raise RuntimeError("data must be a dict") 27 | if code == 0: 28 | code = 200 29 | return render_template(html, **data), code 30 | 31 | 32 | def get_data_from_ajax(noabort=False): 33 | data = dict() 34 | try: 35 | if request.data: 36 | data.update(json.loads(request.data)) 37 | data.update(dict(request.args.items())) 38 | data.update(request.form.items()) 39 | # data.update(request.data) 40 | except Exception, e: 41 | print e.message 42 | if not noabort: 43 | abort(400, u'post 数据体为空或不是合法json') 44 | data.update(request.args.items()) 45 | data.update(request.form.items()) 46 | return data 47 | return data if type(data) == dict else {} 48 | 49 | 50 | def allow_cross_domain(fun): 51 | @wraps(fun) 52 | def wrapper_fun(*args, **kwargs): 53 | rst = make_response(fun(*args, **kwargs)) 54 | rst.headers['Access-Control-Allow-Origin'] = '*' 55 | rst.headers['Access-Control-Allow-Methods'] = 'PUT,GET,POST,DELETE' 56 | allow_headers = "Referer,Accept,Origin,User-Agent" 57 | rst.headers['Access-Control-Allow-Headers'] = allow_headers 58 | return rst 59 | 60 | return wrapper_fun 61 | 62 | 63 | def check_auth(fun): 64 | @wraps(fun) 65 | def wrapper_fun(*args, **kwargs): 66 | params = dict(request.args.items()) # .items() 67 | # 后门 68 | username = params.get('username', None) 69 | if username is not None: 70 | userindex = get_userindex_byname(username) 71 | if userindex is not None: 72 | return fun(*args, userindex=userindex, **kwargs) 73 | 74 | token = params.get('token', None) 75 | if token is None: 76 | abort(401, u"can't find token!") 77 | userindex = get_userindex_bytoken(token) 78 | if userindex is None: 79 | abort(400, u"token is invalid or user is not exist!") 80 | return fun(*args, userindex=userindex, **kwargs) 81 | 82 | return wrapper_fun 83 | 84 | 85 | def check_auth_ext(fun): 86 | @wraps(fun) 87 | def wrapper_fun(*args, **kwargs): 88 | params = dict(request.args.items()) # .items() 89 | # 后门 90 | username = params.get('username', None) 91 | if username is not None: 92 | userindex = get_userindex_byname(username) 93 | if userindex is not None: 94 | if userindex.UserID == '': 95 | abort(403, u"need to complete personal info first!") 96 | return fun(*args, userindex=userindex, **kwargs) 97 | 98 | token = params.get('token', None) 99 | if token is None: 100 | abort(401, u"can't find token!") 101 | userindex = get_userindex_bytoken(token) 102 | if userindex is None: 103 | abort(400, u"token is invalid or user is not exist!") 104 | if userindex.UserID == '': 105 | abort(403, u"need to complete personal info first!") 106 | return fun(*args, userindex=userindex, **kwargs) 107 | 108 | return wrapper_fun 109 | 110 | 111 | def main(): 112 | pass 113 | 114 | 115 | if __name__ == '__main__': 116 | main() 117 | -------------------------------------------------------------------------------- /app/routes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | import os 4 | from flask import request, Flask, jsonify, render_template, redirect, url_for, flash, abort, send_from_directory, \ 5 | Response, session 6 | 7 | from . import app 8 | from .routersutil import * 9 | 10 | 11 | @app.errorhandler(500) 12 | def inner_error(e): 13 | msg = e.description 14 | if request_wants_json(): 15 | return jsonify(jsonutil.json_wrapper(None, 500, msg)), 500 16 | return "inner error!
%s" % msg, 500 17 | 18 | 19 | @app.errorhandler(400) 20 | def params_error(e): 21 | msg = e.description 22 | if msg == -1: 23 | msg = u"不允许访问" 24 | return jsonify(jsonutil.json_wrapper(None, 400, msg)), 400 25 | 26 | 27 | @app.errorhandler(401) 28 | def need_login(e): 29 | msg = e.description 30 | if msg == -1: 31 | msg = u"身份过期或未登录" 32 | return jsonify(jsonutil.json_wrapper(None, 401, msg)), 401 33 | 34 | 35 | @app.errorhandler(403) 36 | def forbid(e): 37 | msg = e.description 38 | if msg == -1: 39 | msg = u"不允许访问" 40 | return jsonify(jsonutil.json_wrapper(None, 403, msg)), 403 41 | 42 | 43 | @app.errorhandler(404) 44 | def page_not_found(e): 45 | msg = e.description 46 | if msg == -1: 47 | msg = u"路径错误或没有该资源" 48 | if request_wants_json(): 49 | return jsonify(jsonutil.json_wrapper(None, 404, msg)), 404 50 | return render_template('404.html', msg=msg), 404 51 | 52 | 53 | @app.route('/', methods=['GET', 'POST']) 54 | @allow_cross_domain 55 | def index_redirect(): 56 | return redirect('index.html') 57 | 58 | 59 | @app.route('/index', methods=['GET', 'POST']) 60 | @allow_cross_domain 61 | def index(): 62 | return render_template('index.html') 63 | 64 | 65 | @app.route('/index/second', methods=['GET', 'POST']) 66 | @allow_cross_domain 67 | def index2(): 68 | return "123" 69 | 70 | 71 | @app.route('/fxck', methods=['get', 'post']) 72 | @allow_cross_domain 73 | def fxck(): 74 | return_data(None, {"12": 1}) 75 | return unicode(request.data) 76 | pass 77 | 78 | 79 | # add other routers 80 | from .routersuser import * 81 | from .routerstxs import * 82 | from .routersjobs import * 83 | 84 | 85 | @app.route('/mockdata', methods=['post']) 86 | @allow_cross_domain 87 | def mock_data(): 88 | data = get_data_from_ajax() 89 | key = data.get("key") 90 | if key != "motherfxcker": 91 | abort(403, "key is not valid!") 92 | 93 | # create user 94 | # student Li 95 | username = u'Li' 96 | password = hashutil.hash_md5('123qwe') 97 | role = UserRole.Student 98 | li_userindex = UserController.create_userindex(username, password, role) 99 | li_userindex.IDNo = u"53**************11" 100 | li_userindex.RealName = u"李某" 101 | li_userindex.Gender = 0 102 | li_userindex.Tele = u"151********" 103 | li_userindex.School = u"同济大学" 104 | li_userindex.StuID = u"1252***" 105 | li_user = UserController.create_user(li_userindex) 106 | 107 | # student Zhou 108 | username = u'Zhou' 109 | password = hashutil.hash_md5('123qwe') 110 | role = UserRole.Student 111 | zhou_userindex = UserController.create_userindex(username, password, role) 112 | zhou_userindex.IDNo = u"36**************13" 113 | zhou_userindex.RealName = u"周某" 114 | zhou_userindex.Gender = 0 115 | zhou_userindex.Tele = u"181********" 116 | zhou_userindex.School = u"同济大学 嘉定校区" 117 | zhou_userindex.StuID = u"1200***" 118 | zhou_user = UserController.create_user(zhou_userindex) 119 | 120 | # agency 121 | # TongjiAgency 122 | username = u'TongjiAgency' 123 | password = hashutil.hash_md5('123qwe') 124 | role = UserRole.Agency 125 | tj_ag_userindex = UserController.create_userindex(username, password, role) 126 | tj_ag_userindex.IDNo = u"35**************13" 127 | tj_ag_userindex.RealName = u"周xx" 128 | tj_ag_userindex.Gender = 0 129 | tj_ag_userindex.Tele = u"181********" 130 | tj_ag_userindex.AgencyName = u"同济兼嘉" 131 | tj_ag_user = UserController.create_user(tj_ag_userindex) 132 | # ZhouAgency 133 | username = u'ZhouAgency' 134 | password = hashutil.hash_md5('123qwe') 135 | role = UserRole.Agency 136 | zhou_ag_userindex = UserController.create_userindex(username, password, role) 137 | zhou_ag_userindex.IDNo = u"25**************13" 138 | zhou_ag_userindex.RealName = u"周xx" 139 | zhou_ag_userindex.Gender = 0 140 | zhou_ag_userindex.Tele = u"181********" 141 | zhou_ag_userindex.AgencyName = u"周氏中介" 142 | zhou_ag_user = UserController.create_user(zhou_ag_userindex) 143 | # HuangAgency 144 | username = u'HuangAgency' 145 | password = hashutil.hash_md5('123qwe') 146 | role = UserRole.Agency 147 | huang_ag_userindex = UserController.create_userindex(username, password, role) 148 | huang_ag_userindex.IDNo = u"45**************13" 149 | huang_ag_userindex.RealName = u"黄xx" 150 | huang_ag_userindex.Gender = 0 151 | huang_ag_userindex.Tele = u"171********" 152 | huang_ag_userindex.AgencyName = u"黄氏中介" 153 | huang_ag_user = UserController.create_user(huang_ag_userindex) 154 | # JinAgency 155 | username = u'JinAgency' 156 | password = hashutil.hash_md5('123qwe') 157 | role = UserRole.Agency 158 | jin_ag_userindex = UserController.create_userindex(username, password, role) 159 | jin_ag_userindex.IDNo = u"53**************13" 160 | jin_ag_userindex.RealName = u"金xx" 161 | jin_ag_userindex.Gender = 0 162 | jin_ag_userindex.Tele = u"131********" 163 | jin_ag_userindex.AgencyName = u"金氏中介" 164 | jin_ag_user = UserController.create_user(jin_ag_userindex) 165 | # Zhen 166 | username = u'ZhenAgency' 167 | password = hashutil.hash_md5('123qwe') 168 | role = UserRole.Agency 169 | zhen_ag_userindex = UserController.create_userindex(username, password, role) 170 | zhen_ag_userindex.IDNo = u"13**************13" 171 | zhen_ag_userindex.RealName = u"郑xx" 172 | zhen_ag_userindex.Gender = 0 173 | zhen_ag_userindex.Tele = u"152********" 174 | zhen_ag_userindex.AgencyName = u"郑氏中介" 175 | zhen_ag_user = UserController.create_user(zhen_ag_userindex) 176 | # Wu 177 | username = u'WuAgency' 178 | password = hashutil.hash_md5('123qwe') 179 | role = UserRole.Agency 180 | wu_ag_userindex = UserController.create_userindex(username, password, role) 181 | wu_ag_userindex.IDNo = u"13**************13" 182 | wu_ag_userindex.RealName = u"吴xx" 183 | wu_ag_userindex.Gender = 0 184 | wu_ag_userindex.Tele = u"183********" 185 | wu_ag_userindex.AgencyName = u"吴氏中介" 186 | wu_ag_userindex.save() 187 | wu_ag_user = UserController.create_user(wu_ag_userindex) 188 | ############################################################# 189 | # jobs 190 | # 1 191 | title = u"上海房车露营展览会志愿者" 192 | jobtime = u"8h" 193 | place = u"上海汽车会展中心" 194 | salary = u"130" 195 | day = u"每天" 196 | demand = u"130元每天,包饭,要求人员认真负责。" 197 | job1 = JobController.create_jobinfo(zhou_ag_userindex, title, jobtime, place, salary, day, demand) 198 | zhou_ag_userindex.JobTxMap[unicode(job1.id)] = "" 199 | zhou_ag_userindex.save() 200 | # 2 201 | title = u"家教" 202 | jobtime = u"2H" 203 | place = u"学生家中" 204 | salary = u"130" 205 | day = u"一周1-2次" 206 | demand = u"教学科目有水平,认真负责" 207 | job2 = JobController.create_jobinfo(zhou_ag_userindex, title, jobtime, place, salary, day, demand) 208 | zhou_ag_userindex.JobTxMap[unicode(job2.id)] = "" 209 | zhou_ag_userindex.save() 210 | # 3 211 | title = u"托班代课" 212 | jobtime = u"8H" 213 | place = u"安亭一处辅导班中" 214 | salary = u"180" 215 | day = u"1天" 216 | demand = u"教学科目有水平,认真负责" 217 | job3 = JobController.create_jobinfo(zhou_ag_userindex, title, jobtime, place, salary, day, demand) 218 | zhou_ag_userindex.JobTxMap[unicode(job3.id)] = "" 219 | zhou_ag_userindex.save() 220 | 221 | # 4 222 | title = u"充场" 223 | jobtime = u"2H" 224 | place = u"同济嘉定校区" 225 | salary = u"40" 226 | day = u"1天" 227 | demand = u"无" 228 | job4 = JobController.create_jobinfo(huang_ag_userindex, title, jobtime, place, salary, day, demand) 229 | huang_ag_userindex.JobTxMap[unicode(job4.id)] = "" 230 | huang_ag_userindex.save() 231 | # 5 232 | title = u"摄像" 233 | jobtime = u"8H:30M" 234 | place = u"同济嘉定校区" 235 | salary = u"700" 236 | day = u"1天" 237 | demand = u"有专业摄影机器,有摄影经验" 238 | job5 = JobController.create_jobinfo(huang_ag_userindex, title, jobtime, place, salary, day, demand) 239 | huang_ag_userindex.JobTxMap[unicode(job5.id)] = "" 240 | huang_ag_userindex.save() 241 | # 6 242 | title = u"F1大奖赛上海站工作人员" 243 | jobtime = u"8H" 244 | place = u"上海赛车场水景广场" 245 | salary = u"120" 246 | day = u"3天" 247 | demand = u"120每天/包饭" 248 | job6 = JobController.create_jobinfo(huang_ag_userindex, title, jobtime, place, salary, day, demand) 249 | huang_ag_userindex.JobTxMap[unicode(job6.id)] = "" 250 | huang_ag_userindex.save() 251 | 252 | # 7 253 | title = u"陆家嘴正大广场促销员" 254 | jobtime = u"9H" 255 | place = u"陆家嘴正大广场" 256 | salary = u"180" 257 | day = u"5天" 258 | demand = u"180+提成,要求身高165mm以上的女生" 259 | job7 = JobController.create_jobinfo(jin_ag_userindex, title, jobtime, place, salary, day, demand) 260 | jin_ag_userindex.JobTxMap[unicode(job7.id)] = "" 261 | jin_ag_userindex.save() 262 | # 8 263 | title = u"微软宣讲会支持" 264 | jobtime = u"4H" 265 | place = u"同济嘉定校区" 266 | salary = u"100" 267 | day = u"1天" 268 | demand = u"100+包饭" 269 | job8 = JobController.create_jobinfo(jin_ag_userindex, title, jobtime, place, salary, day, demand) 270 | jin_ag_userindex.JobTxMap[unicode(job8.id)] = "" 271 | jin_ag_userindex.save() 272 | # 9 273 | title = u"京东开学季路演支持" 274 | jobtime = u"8H" 275 | place = u"同济嘉定校区" 276 | salary = u"130" 277 | day = u"1天" 278 | demand = u"无" 279 | job9 = JobController.create_jobinfo(jin_ag_userindex, title, jobtime, place, salary, day, demand) 280 | jin_ag_userindex.JobTxMap[unicode(job9.id)] = "" 281 | jin_ag_userindex.save() 282 | # 10 283 | title = u"京东开学季传单发放" 284 | jobtime = u"2H" 285 | place = u"同济嘉定校区" 286 | salary = u"60" 287 | day = u"1天" 288 | demand = u"无" 289 | job10 = JobController.create_jobinfo(jin_ag_userindex, title, jobtime, place, salary, day, demand) 290 | jin_ag_userindex.JobTxMap[unicode(job10.id)] = "" 291 | jin_ag_userindex.save() 292 | 293 | # 11 294 | title = u"EVCARD问卷调查志愿者" 295 | jobtime = u"5-6H" 296 | place = u"上海市" 297 | salary = u"170" 298 | day = u"30天" 299 | demand = u"会开车且注册过EVCARD,完成指定任务" 300 | job11 = JobController.create_jobinfo(zhen_ag_userindex, title, jobtime, place, salary, day, demand) 301 | zhen_ag_userindex.JobTxMap[unicode(job11.id)] = "" 302 | zhen_ag_userindex.save() 303 | # 12 304 | title = u"新阳辅导团队" 305 | jobtime = u"3H" 306 | place = u"黄渡新阳辅导中心" 307 | salary = u"110" 308 | day = u"至少一学期" 309 | demand = u"110包饭,认真负责" 310 | job12 = JobController.create_jobinfo(zhen_ag_userindex, title, jobtime, place, salary, day, demand) 311 | zhen_ag_userindex.JobTxMap[unicode(job12.id)] = "" 312 | zhen_ag_userindex.save() 313 | # 13 314 | title = u"支点教育助教" 315 | jobtime = u"8H: 30M" 316 | place = u"嘉定区天祝路嘉鼎国际大厦" 317 | salary = u"180" 318 | day = u"180天" 319 | demand = u"解题能力强,思路清晰,思维灵活,工作踏实" 320 | job13 = JobController.create_jobinfo(zhen_ag_userindex, title, jobtime, place, salary, day, demand) 321 | zhen_ag_userindex.JobTxMap[unicode(job13.id)] = "" 322 | zhen_ag_userindex.save() 323 | 324 | # 14 325 | title = u"晋元高级中学教师运动会" 326 | jobtime = u"3H" 327 | place = u"晋元高级中学" 328 | salary = u"130" 329 | day = u"1天" 330 | demand = u"无" 331 | job14 = JobController.create_jobinfo(zhen_ag_userindex, title, jobtime, place, salary, day, demand) 332 | zhen_ag_userindex.JobTxMap[unicode(job14.id)] = "" 333 | zhen_ag_userindex.save() 334 | # 15 335 | title = u"元旦赛场迎新跑" 336 | jobtime = u"8H" 337 | place = u"上海赛车场" 338 | salary = u"120" 339 | day = u"1天" 340 | demand = u"120包饭,仅限女生报名" 341 | job15 = JobController.create_jobinfo(zhen_ag_userindex, title, jobtime, place, salary, day, demand) 342 | zhen_ag_userindex.JobTxMap[unicode(job15.id)] = "" 343 | zhen_ag_userindex.save() 344 | # 16 345 | title = u"世界耐力锦标赛志愿者" 346 | jobtime = u"8H" 347 | place = u"上海赛车场" 348 | salary = u"120" 349 | day = u"1天" 350 | demand = u"120包饭" 351 | job16 = JobController.create_jobinfo(zhen_ag_userindex, title, jobtime, place, salary, day, demand) 352 | zhen_ag_userindex.JobTxMap[unicode(job16.id)] = "" 353 | zhen_ag_userindex.save() 354 | 355 | # 17 356 | title = u"农场嘉年华健康跑" 357 | jobtime = u"8H" 358 | place = u"上海市嘉定区博园路4285号" 359 | salary = u"100" 360 | day = u"1天" 361 | demand = u"无" 362 | job17 = JobController.create_jobinfo(tj_ag_userindex, title, jobtime, place, salary, day, demand) 363 | tj_ag_userindex.JobTxMap[unicode(job17.id)] = "" 364 | tj_ag_userindex.save() 365 | # 18 366 | title = u"无人机电子音乐嘉年华志愿者" 367 | jobtime = u"3H" 368 | place = u"上海汽车博览公园" 369 | salary = u"80" 370 | day = u"1天" 371 | demand = u"无" 372 | job18 = JobController.create_jobinfo(tj_ag_userindex, title, jobtime, place, salary, day, demand) 373 | tj_ag_userindex.JobTxMap[unicode(job18.id)] = "" 374 | tj_ag_userindex.save() 375 | # 19 376 | title = u"篮球赛主持人" 377 | jobtime = u"4H" 378 | place = u"同济嘉定校区" 379 | salary = u"200" 380 | day = u"1天" 381 | demand = u"女生,有主持经验者" 382 | job19 = JobController.create_jobinfo(tj_ag_userindex, title, jobtime, place, salary, day, demand) 383 | tj_ag_userindex.JobTxMap[unicode(job19.id)] = "" 384 | tj_ag_userindex.save() 385 | # 20 386 | title = u"国际小丑节" 387 | jobtime = u"6H: 30M" 388 | place = u"同济嘉定校区" 389 | salary = u"100" 390 | day = u"2天" 391 | demand = u"无" 392 | job20 = JobController.create_jobinfo(tj_ag_userindex, title, jobtime, place, salary, day, demand) 393 | tj_ag_userindex.JobTxMap[unicode(job20.id)] = "" 394 | tj_ag_userindex.save() 395 | 396 | return return_data(data={"result": "finish"}) 397 | 398 | 399 | def main(): 400 | pass 401 | 402 | 403 | if __name__ == '__main__': 404 | main() 405 | -------------------------------------------------------------------------------- /app/static/css/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBD-Forum/N0020-Tongjia/ab6550b910559daf380aeb6b4dbd4df46ebbfdd8/app/static/css/.gitkeep -------------------------------------------------------------------------------- /app/static/imgs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBD-Forum/N0020-Tongjia/ab6550b910559daf380aeb6b4dbd4df46ebbfdd8/app/static/imgs/.gitkeep -------------------------------------------------------------------------------- /app/static/imgs/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBD-Forum/N0020-Tongjia/ab6550b910559daf380aeb6b4dbd4df46ebbfdd8/app/static/imgs/favicon.png -------------------------------------------------------------------------------- /app/static/indextest.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | hhh 9 | 10 | -------------------------------------------------------------------------------- /app/static/js/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBD-Forum/N0020-Tongjia/ab6550b910559daf380aeb6b4dbd4df46ebbfdd8/app/static/js/.gitkeep -------------------------------------------------------------------------------- /app/templates/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 未找到! 6 | 7 | 8 |

路径错误或没有该资源

9 |

{{ msg }}

10 | 11 | -------------------------------------------------------------------------------- /app/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block head%} 4 | 5 | {%endblock%} 6 | 7 | {% block body %} 8 | 9 | inbody 10 | 11 | 12 | {% endblock %} -------------------------------------------------------------------------------- /app/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | TEMP 4 | 5 | 6 | {% block head %} 7 | {% endblock %} 8 | 9 | 10 | 11 | 12 | {% with messages = get_flashed_messages() %} 13 | {% if messages %} 14 |
    15 | {% for message in messages %} 16 |
  • {{ message }}
  • 17 | {% endfor %} 18 |
19 | {% endif %} 20 | {% endwith %} 21 | 22 | 23 | {% block body %} 24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /app/templates/login.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | 4 | 5 | {% block body %} 6 |
7 | {{ form.csrf_token }} 8 | {{ form.username.label }} {{ form.username(size=20) }} 9 |
10 | {{ form.password.label }} {{ form.password(size=20) }} 11 |
12 | 13 |
14 | 15 | 16 | {{ msg }} 17 |
18 | {% endblock %} -------------------------------------------------------------------------------- /app/utils/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | def main(): 6 | pass 7 | 8 | 9 | if __name__ == '__main__': 10 | main() 11 | -------------------------------------------------------------------------------- /app/utils/hashutil.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | import hashlib 6 | 7 | 8 | def hash_md5(s): 9 | return hashlib.md5(s).hexdigest() 10 | 11 | 12 | def main(): 13 | pass 14 | 15 | 16 | if __name__ == '__main__': 17 | main() 18 | -------------------------------------------------------------------------------- /app/utils/jsonutil.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import json 5 | import traceback 6 | from bson import ObjectId 7 | 8 | 9 | def json_wrapper(obj, error=0, msg='', str_type=False): 10 | d = {'err': error, 'msg': msg, 'data': obj} 11 | if str_type: 12 | return json.dumps(d) 13 | else: 14 | return d 15 | 16 | 17 | def parse_json(json_str): 18 | try: 19 | return json.loads(json_str) 20 | except: 21 | print "json decoded failed for %s" % json_str 22 | return None 23 | 24 | 25 | class JSONEncoder(json.JSONEncoder): 26 | def default(self, o): 27 | if isinstance(o, ObjectId): 28 | return unicode(o) 29 | return json.JSONEncoder.default(self, o) 30 | 31 | 32 | def to_json(data): 33 | try: 34 | return json.dumps(data, cls=JSONEncoder) 35 | except Exception, e: 36 | print "wrong in dumps data to json: %s" % e.message 37 | traceback.print_exc() 38 | 39 | 40 | def main(): 41 | pass 42 | 43 | 44 | if __name__ == '__main__': 45 | main() 46 | -------------------------------------------------------------------------------- /app/utils/util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import functools 4 | import time 5 | 6 | 7 | def class_params_check(*types, **kwtypes): 8 | """ 9 | check the parameters of a class function, usage: @class_params_check(int, str, (int, str), key1=list, key2=(list, tuple)) 10 | """ 11 | 12 | def _decoration(func): 13 | @functools.wraps(func) 14 | def _inner(*args, **kwargs): 15 | result = [isinstance(_param, _type) for _param, _type in zip(args[1:], types)] 16 | assert all(result), "params_chack: invalid parameters in " + func.__name__ 17 | result = [isinstance(kwargs[_param], kwtypes[_param]) for _param in kwargs if _param in kwtypes] 18 | # print result 19 | assert all(result), "params_chack: invalid parameters in " + func.__name__ 20 | return func(*args, **kwargs) 21 | 22 | return _inner 23 | 24 | return _decoration 25 | 26 | 27 | def params_check(*types, **kwtypes): 28 | """ 29 | check the parameters of a function, usage: @params_chack(int, str, (int, str), key1=list, key2=(list, tuple)) 30 | """ 31 | 32 | def _decoration(func): 33 | @functools.wraps(func) 34 | def _inner(*args, **kwargs): 35 | result = [isinstance(_param, _type) for _param, _type in zip(args, types)] 36 | assert all(result), "params_chack: invalid parameters in " + func.__name__ 37 | result = [isinstance(kwargs[_param], kwtypes[_param]) for _param in kwargs if _param in kwtypes] 38 | # print result 39 | assert all(result), "params_chack: invalid parameters in " + func.__name__ 40 | return func(*args, **kwargs) 41 | 42 | return _inner 43 | 44 | return _decoration 45 | 46 | 47 | def get_time(raw=False): 48 | if raw: 49 | return time.time() 50 | return int(time.time()) 51 | 52 | 53 | def main(): 54 | pass 55 | 56 | 57 | if __name__ == '__main__': 58 | main() 59 | -------------------------------------------------------------------------------- /chaincode/JobInfo/JobInfo.go: -------------------------------------------------------------------------------- 1 | // ============================================================================================================================ 2 | // 本智能合约用于兼职信息管理 3 | // 功能包括:兼职信息的增、删、改、查,统计数据的更新,订单信息的添加 4 | // ============================================================================================================================ 5 | 6 | package main 7 | 8 | import ( 9 | "encoding/json" 10 | "errors" 11 | "fmt" 12 | "github.com/hyperledger/fabric/core/chaincode/shim" 13 | "github.com/hyperledger/fabric/core/util" 14 | "strconv" 15 | ) 16 | 17 | type SimpleChaincode struct { 18 | } 19 | 20 | // ============================================================================================================================ 21 | // JobInfo struct 22 | // ============================================================================================================================ 23 | type JobInfoStruct struct { 24 | JobID string 25 | UserID string 26 | AgencyName string 27 | JobDetail JobStaticInfoStruct 28 | Txs []string 29 | TotalApplied string 30 | TotalWaitCheck string 31 | TotalHired string 32 | TotalSettled string 33 | } 34 | 35 | // ============================================================================================================================ 36 | // UserStaticInfo struct 37 | // ============================================================================================================================ 38 | type JobStaticInfoStruct struct { 39 | JobTime string 40 | Place string 41 | Salary string 42 | Day string 43 | Demand string 44 | Title string 45 | } 46 | 47 | const UserInfoChaincodeID string = "9d29747f0b642ed65f481fbc1132d518834b3099671ad5d86feb8609202197f26cefcca348942ce9facdbe8312b5d7ee5598a6d9522c34ae9755720c1176a598" 48 | 49 | // ============================================================================================================================ 50 | // Init function 51 | // ============================================================================================================================ 52 | 53 | func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { 54 | return nil, nil 55 | } 56 | 57 | // ============================================================================================================================ 58 | // Invoke function is the entry point for Invocations 59 | // ============================================================================================================================ 60 | func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { 61 | 62 | // Handle different functions 63 | if function == "init" { 64 | return t.Init(stub, "init", args) 65 | } else if function == "add" { //add a new job 66 | return t.Add(stub, args) 67 | } else if function == "delete" { //deletes an job from its state 68 | return t.Delete(stub, args) 69 | } else if function == "edit" { //change the infor of the job 70 | return t.Edit(stub, args) 71 | } else if function == "addTX" { //add a new TX 72 | return t.AddTX(stub, args) 73 | } else if function == "addTotalApplied" { //add 1 when a student applied the job 74 | return t.AddTotalApplied(stub, args) 75 | } else if function == "addTotalWaitCheck" { //add 1 when auto check not passed 76 | return t.AddTotalWaitCheck(stub, args) 77 | } else if function == "addTotalHired" { //add 1 when auto check passed or agency check passed 78 | return t.AddTotalHired(stub, args) 79 | } else if function == "addTotalSettled" { //add 1 when auto settle passed or agency settle passed 80 | return t.AddTotalSettled(stub, args) 81 | } 82 | 83 | return nil, errors.New("Received unknown function invocation") 84 | } 85 | 86 | // ============================================================================================================================ 87 | // Add function is used for adding a new job 88 | // 2 input 89 | // "JobID","JobInfo" 90 | // ============================================================================================================================ 91 | func (t *SimpleChaincode) Add(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 92 | var err error 93 | if len(args) != 2 { 94 | return nil, errors.New("Incorrect number of arguments. Expecting 2. ") 95 | } 96 | JobID := args[0] 97 | JobInfo := args[1] 98 | JobTest, _ := stub.GetState(JobID) 99 | 100 | //test if the job has been existed 101 | if JobTest != nil { 102 | return nil, errors.New("the user is existed") 103 | } 104 | 105 | // add the job 106 | err = stub.PutState(JobID, []byte(JobInfo)) 107 | if err != nil { 108 | return nil, errors.New("Failed to add the job") 109 | } 110 | 111 | var JobInfoJsonType JobInfoStruct //json type to accept the JobInfo from state 112 | err = json.Unmarshal([]byte(JobInfo), &JobInfoJsonType) 113 | if err != nil { 114 | fmt.Println("error:", err) 115 | } 116 | 117 | //invoke UserInfo chaincode to add this job`s ID attach to the agency who publish this job 118 | f := "addTX" 119 | invokeArgs := util.ToChaincodeArgs(f, JobInfoJsonType.UserID, JobInfoJsonType.JobID) 120 | response, err := stub.InvokeChaincode(UserInfoChaincodeID, invokeArgs) 121 | if err != nil { 122 | errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error()) 123 | fmt.Printf(errStr) 124 | return nil, errors.New(errStr) 125 | } 126 | fmt.Printf("Invoke chaincode successful. Got response %s", string(response)) 127 | 128 | return nil, nil 129 | } 130 | 131 | // ============================================================================================================================ 132 | // Delete function is used for deleting a job 133 | // 1 input 134 | // "JobID" 135 | // ============================================================================================================================ 136 | func (t *SimpleChaincode) Delete(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 137 | var err error 138 | if len(args) != 1 { 139 | return nil, errors.New("Incorrect number of arguments. Expecting 1. ") 140 | } 141 | JobID := args[0] 142 | JobInfo, err := stub.GetState(JobID) 143 | 144 | //test if the job has been existed 145 | if err != nil { 146 | return nil, errors.New("The job never been exited") 147 | } 148 | 149 | if JobInfo == nil { 150 | return nil, errors.New("The job`s information is empty!") 151 | } 152 | 153 | err = stub.DelState(JobID) //remove the key from chaincode state 154 | if err != nil { 155 | return nil, errors.New("Failed to delete this job information! ") 156 | } 157 | 158 | return nil, nil 159 | } 160 | 161 | // ============================================================================================================================ 162 | // Edit function is used for changing the job's info 163 | // 2 input 164 | // "JobID","NewJobInfo" 165 | // ============================================================================================================================ 166 | func (t *SimpleChaincode) Edit(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 167 | var err error 168 | if len(args) != 2 { 169 | return nil, errors.New("Incorrect number of arguments. Expecting 2. ") 170 | } 171 | JobID := args[0] 172 | NewJobInfo := args[1] 173 | OldJobInfo, err := stub.GetState(JobID) 174 | 175 | //test if the job has been existed 176 | if err != nil { 177 | return nil, errors.New("The job never been exited") 178 | } 179 | 180 | if OldJobInfo == nil { 181 | return nil, errors.New("The job`s information is empty!") 182 | } 183 | 184 | // edit the job 185 | err = stub.PutState(JobID, []byte(NewJobInfo)) 186 | if err != nil { 187 | return nil, errors.New("Failed to edit the job") 188 | } 189 | 190 | return nil, nil 191 | } 192 | 193 | // ============================================================================================================================ 194 | // AddTotalApplied function is used to add 1 when a student applied the job 195 | // 1 input 196 | // "JobID" 197 | // ============================================================================================================================ 198 | func (t *SimpleChaincode) AddTotalApplied(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 199 | var err error 200 | if len(args) != 1 { 201 | return nil, errors.New("Incorrect number of arguments. Expecting 1. ") 202 | } 203 | JobID := args[0] 204 | JobInfo, err := stub.GetState(JobID) 205 | 206 | //test if the job has been existed 207 | if err != nil { 208 | return nil, errors.New("The job never been exited") 209 | } 210 | if JobInfo == nil { 211 | return nil, errors.New("The job`s information is empty!") 212 | } 213 | 214 | var JobInfoJsonType JobInfoStruct //json type to accept the JobInfo from state 215 | 216 | err = json.Unmarshal(JobInfo, &JobInfoJsonType) 217 | if err != nil { 218 | fmt.Println("error:", err) 219 | } 220 | 221 | var TotalAppliedValue int 222 | TotalAppliedValue, _ = strconv.Atoi(string(JobInfoJsonType.TotalApplied)) 223 | TotalAppliedValue++ 224 | JobInfoJsonType.TotalApplied = strconv.Itoa(TotalAppliedValue) 225 | 226 | // put the new score into state 227 | a, err := json.Marshal(JobInfoJsonType) 228 | if err != nil { 229 | return nil, err 230 | } 231 | err = stub.PutState(JobID, []byte(a)) 232 | if err != nil { 233 | return nil, errors.New("Failed to putstate") 234 | } 235 | 236 | return nil, nil 237 | } 238 | 239 | // ============================================================================================================================ 240 | // AddTotalWaitCheck function is used to add 1 when auto check not passed 241 | // 1 input 242 | // "JobID","1/-1" 243 | // ============================================================================================================================ 244 | func (t *SimpleChaincode) AddTotalWaitCheck(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 245 | var err error 246 | if len(args) != 2 { 247 | return nil, errors.New("Incorrect number of arguments. Expecting 2. ") 248 | } 249 | JobID := args[0] 250 | Num, _ := strconv.Atoi(args[1]) 251 | JobInfo, err := stub.GetState(JobID) 252 | 253 | //test if the job has been existed 254 | if err != nil { 255 | return nil, errors.New("The job never been exited") 256 | } 257 | if JobInfo == nil { 258 | return nil, errors.New("The job`s information is empty!") 259 | } 260 | 261 | var JobInfoJsonType JobInfoStruct //json type to accept the JobInfo from state 262 | 263 | err = json.Unmarshal(JobInfo, &JobInfoJsonType) 264 | if err != nil { 265 | fmt.Println("error:", err) 266 | } 267 | 268 | var TotalWaitCheckValue int 269 | TotalWaitCheckValue, _ = strconv.Atoi(string(JobInfoJsonType.TotalWaitCheck)) 270 | TotalWaitCheckValue += Num 271 | JobInfoJsonType.TotalWaitCheck = strconv.Itoa(TotalWaitCheckValue) 272 | 273 | // put the new score into state 274 | a, err := json.Marshal(JobInfoJsonType) 275 | if err != nil { 276 | return nil, err 277 | } 278 | err = stub.PutState(JobID, []byte(a)) 279 | if err != nil { 280 | return nil, errors.New("Failed to putstate") 281 | } 282 | 283 | return nil, nil 284 | } 285 | 286 | // ============================================================================================================================ 287 | // AddTotalHired function is used to add 1 when auto check passed or agency check passed 288 | // 1 input 289 | // "JobID" 290 | // ============================================================================================================================ 291 | func (t *SimpleChaincode) AddTotalHired(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 292 | var err error 293 | if len(args) != 1 { 294 | return nil, errors.New("Incorrect number of arguments. Expecting 1. ") 295 | } 296 | JobID := args[0] 297 | JobInfo, err := stub.GetState(JobID) 298 | 299 | //test if the job has been existed 300 | if err != nil { 301 | return nil, errors.New("The job never been exited") 302 | } 303 | if JobInfo == nil { 304 | return nil, errors.New("The job`s information is empty!") 305 | } 306 | 307 | var JobInfoJsonType JobInfoStruct //json type to accept the JobInfo from state 308 | 309 | err = json.Unmarshal(JobInfo, &JobInfoJsonType) 310 | if err != nil { 311 | fmt.Println("error:", err) 312 | } 313 | 314 | var TotalHiredValue int 315 | TotalHiredValue, _ = strconv.Atoi(string(JobInfoJsonType.TotalHired)) 316 | TotalHiredValue++ 317 | JobInfoJsonType.TotalHired = strconv.Itoa(TotalHiredValue) 318 | 319 | // put the new score into state 320 | a, err := json.Marshal(JobInfoJsonType) 321 | if err != nil { 322 | return nil, err 323 | } 324 | err = stub.PutState(JobID, []byte(a)) 325 | if err != nil { 326 | return nil, errors.New("Failed to putstate") 327 | } 328 | 329 | return nil, nil 330 | } 331 | 332 | // ============================================================================================================================ 333 | // AddTotalSettled function is used to add 1 when auto settle passed or agency settle passed 334 | // 1 input 335 | // "JobID" 336 | // ============================================================================================================================ 337 | func (t *SimpleChaincode) AddTotalSettled(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 338 | var err error 339 | if len(args) != 1 { 340 | return nil, errors.New("Incorrect number of arguments. Expecting 1. ") 341 | } 342 | JobID := args[0] 343 | JobInfo, err := stub.GetState(JobID) 344 | 345 | //test if the job has been existed 346 | if err != nil { 347 | return nil, errors.New("The job never been exited") 348 | } 349 | if JobInfo == nil { 350 | return nil, errors.New("The job`s information is empty!") 351 | } 352 | 353 | var JobInfoJsonType JobInfoStruct //json type to accept the JobInfo from state 354 | 355 | err = json.Unmarshal(JobInfo, &JobInfoJsonType) 356 | if err != nil { 357 | fmt.Println("error:", err) 358 | } 359 | 360 | var TotalSettledValue int 361 | TotalSettledValue, _ = strconv.Atoi(string(JobInfoJsonType.TotalSettled)) 362 | TotalSettledValue++ 363 | JobInfoJsonType.TotalSettled = strconv.Itoa(TotalSettledValue) 364 | 365 | // put the new score into state 366 | a, err := json.Marshal(JobInfoJsonType) 367 | if err != nil { 368 | return nil, err 369 | } 370 | err = stub.PutState(JobID, []byte(a)) 371 | if err != nil { 372 | return nil, errors.New("Failed to putstate") 373 | } 374 | 375 | return nil, nil 376 | } 377 | 378 | // ============================================================================================================================ 379 | // AddTX function is used to add TXID for the job 380 | // 1 input 381 | // "JobID","TXID" 382 | // ============================================================================================================================ 383 | func (t *SimpleChaincode) AddTX(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 384 | var err error 385 | if len(args) != 2 { 386 | return nil, errors.New("Incorrect number of arguments. Expecting 2. ") 387 | } 388 | JobID := args[0] 389 | TXID := args[1] 390 | JobInfo, err := stub.GetState(JobID) 391 | 392 | //test if the job has been existed 393 | if err != nil { 394 | return nil, errors.New("The job never been exited") 395 | } 396 | if JobInfo == nil { 397 | return nil, errors.New("The job`s information is empty!") 398 | } 399 | 400 | var JobInfoJsonType JobInfoStruct //json type to accept the JobInfo from state 401 | 402 | err = json.Unmarshal(JobInfo, &JobInfoJsonType) 403 | if err != nil { 404 | fmt.Println("error:", err) 405 | } 406 | 407 | JobInfoJsonType.Txs = append(JobInfoJsonType.Txs, TXID) 408 | 409 | // put the new info into state 410 | a, err := json.Marshal(JobInfoJsonType) 411 | if err != nil { 412 | return nil, err 413 | } 414 | err = stub.PutState(JobID, []byte(a)) 415 | if err != nil { 416 | return nil, errors.New("Failed to putstate") 417 | } 418 | 419 | return nil, nil 420 | } 421 | 422 | // ============================================================================================================================ 423 | // Query function is the entry point for Queries 424 | // ============================================================================================================================ 425 | func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { 426 | 427 | if function == "queryJobInfo" { 428 | return t.QueryJobInfo(stub, args) 429 | } else if function == "queryAgencyID" { 430 | return t.QueryAgencyID(stub, args) 431 | } else if function == "querySalary" { 432 | return t.QuerySalary(stub, args) 433 | } 434 | 435 | return nil, errors.New("failed to query") 436 | 437 | } 438 | 439 | // ============================================================================================================================ 440 | // QueryJobInfo function is used to return the whole information of the job. 441 | // 1 input 442 | // "JobID" 443 | // ============================================================================================================================ 444 | func (t *SimpleChaincode) QueryJobInfo(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 445 | if len(args) != 1 { 446 | return nil, errors.New("Incorrect number of arguments. Expecting 1 ") 447 | } 448 | JobID := args[0] 449 | 450 | // Get the state from the ledger 451 | JobInfo, err := stub.GetState(JobID) 452 | if err != nil { 453 | jsonResp := "{\"Error\":\"Failed to get state for " + JobID + "\"}" 454 | return nil, errors.New(jsonResp) 455 | } 456 | 457 | if JobInfo == nil { 458 | jsonResp := "{\"Error\":\"Nil content for " + JobID + "\"}" 459 | return nil, errors.New(jsonResp) 460 | } 461 | 462 | return JobInfo, nil 463 | } 464 | 465 | // ============================================================================================================================ 466 | // QueryAgencyID function is used to query the agency`ID use the job`ID who published . 467 | // 1 input 468 | // "JobID" 469 | // ============================================================================================================================ 470 | func (t *SimpleChaincode) QueryAgencyID(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 471 | var err error 472 | if len(args) != 1 { 473 | return nil, errors.New("Incorrect number of arguments. Expecting 1 ") 474 | } 475 | JobID := args[0] 476 | JobInfo, err := stub.GetState(JobID) 477 | 478 | //test if the job has been existed 479 | if err != nil { 480 | return nil, errors.New("The job never been exited") 481 | } 482 | if JobInfo == nil { 483 | return nil, errors.New("The job`s information is empty!") 484 | } 485 | 486 | var JobInfoJsonType JobInfoStruct //json type to accept the JobInfo from state 487 | 488 | err = json.Unmarshal(JobInfo, &JobInfoJsonType) 489 | if err != nil { 490 | fmt.Println("error:", err) 491 | } 492 | 493 | return []byte(JobInfoJsonType.UserID), nil 494 | } 495 | 496 | // ============================================================================================================================ 497 | // QuerySalary function is used to query the salary use the job`ID who published . 498 | // 1 input 499 | // "JobID" 500 | // ============================================================================================================================ 501 | func (t *SimpleChaincode) QuerySalary(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 502 | var err error 503 | if len(args) != 1 { 504 | return nil, errors.New("Incorrect number of arguments. Expecting 1 ") 505 | } 506 | JobID := args[0] 507 | JobInfo, err := stub.GetState(JobID) 508 | 509 | //test if the job has been existed 510 | if err != nil { 511 | return nil, errors.New("The job never been exited") 512 | } 513 | if JobInfo == nil { 514 | return nil, errors.New("The job`s information is empty!") 515 | } 516 | 517 | var JobInfoJsonType JobInfoStruct //json type to accept the JobInfo from state 518 | 519 | err = json.Unmarshal(JobInfo, &JobInfoJsonType) 520 | if err != nil { 521 | fmt.Println("error:", err) 522 | } 523 | 524 | return []byte(JobInfoJsonType.JobDetail.Salary), nil 525 | } 526 | 527 | func main() { 528 | err := shim.Start(new(SimpleChaincode)) 529 | if err != nil { 530 | fmt.Printf("Error starting Simple chaincode: %s", err) 531 | } 532 | } 533 | -------------------------------------------------------------------------------- /chaincode/TX/TX.go: -------------------------------------------------------------------------------- 1 | // ============================================================================================================================ 2 | // 本智能合约用于TX管理 3 | // 功能包括:TX生成、查询,状态变更 4 | // ============================================================================================================================ 5 | 6 | package main 7 | 8 | import ( 9 | "encoding/json" 10 | "errors" 11 | "fmt" 12 | "github.com/hyperledger/fabric/core/chaincode/shim" 13 | "github.com/hyperledger/fabric/core/util" 14 | "strconv" 15 | "strings" 16 | ) 17 | 18 | type SimpleChaincode struct { 19 | } 20 | 21 | // ============================================================================================================================ 22 | // TXInfo struct 23 | // ============================================================================================================================ 24 | type TXInfoStruct struct { 25 | JobID string 26 | UserID string 27 | ApplyTime string 28 | TxID string 29 | Status string 30 | StuScore string 31 | AgencyScore string 32 | } 33 | 34 | func (t *SimpleChaincode) GetJobChaincodeToCall() string { 35 | chainCodeToCall := "7147861cb80f5447b0ee974bc917935cc8f65bd89a271095af7e0f7cb8184a7dccdbb93a43fce11d24c7532743c7d22c0fa68c6f6bbc29bb8a92f2e98b2d92ae" 36 | return chainCodeToCall 37 | } 38 | 39 | func (t *SimpleChaincode) GetUserChaincodeToCall() string { 40 | chainCodeToCall := "9d29747f0b642ed65f481fbc1132d518834b3099671ad5d86feb8609202197f26cefcca348942ce9facdbe8312b5d7ee5598a6d9522c34ae9755720c1176a598" 41 | return chainCodeToCall 42 | } 43 | 44 | // ============================================================================================================================ 45 | // Init function 46 | // ============================================================================================================================ 47 | 48 | func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { 49 | return nil, nil 50 | } 51 | 52 | // ============================================================================================================================ 53 | // Invoke function is the entry point for Invocations 54 | // ============================================================================================================================ 55 | func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { 56 | 57 | // Handle different functions 58 | if function == "init" { 59 | return t.Init(stub, "init", args) 60 | } else if function == "create" { //create a tx when a student applied a job and auto to check this application 61 | return t.Create(stub, args) 62 | } else if function == "artificialCheck" { //agency check this application when auto check not passed 63 | return t.ArtificialCheck(stub, args) 64 | } else if function == "evaluate" { //student and agancy evaluate each other 65 | return t.Evaluate(stub, args) 66 | } 67 | 68 | return nil, errors.New("Received unknown function invocation") 69 | } 70 | 71 | // ============================================================================================================================ 72 | // Create function is used to create a tx when a student applied a job and auto to check this application 73 | // 2 input 74 | // "TxID","TxInfo" 75 | // ============================================================================================================================ 76 | func (t *SimpleChaincode) Create(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 77 | var err error 78 | if len(args) != 2 { 79 | return nil, errors.New("Incorrect number of arguments. Expecting 2. ") 80 | } 81 | TxID := args[0] 82 | TxInfo := args[1] 83 | TxTest, _ := stub.GetState(TxID) 84 | 85 | //test if the TX has been existed 86 | if TxTest != nil { 87 | return nil, errors.New("the Tx is existed") 88 | } 89 | 90 | // add the Tx 91 | err = stub.PutState(TxID, []byte(TxInfo)) 92 | if err != nil { 93 | return nil, errors.New("Failed to add the user") 94 | } 95 | 96 | var TXInfoJsonType TXInfoStruct //json type to accept the TxInfo from state 97 | 98 | err = json.Unmarshal([]byte(TxInfo), &TXInfoJsonType) 99 | if err != nil { 100 | fmt.Println("error:", err) 101 | } 102 | 103 | //attach the TxID to related job 104 | //invoke JobInfo chaincode to add this TxID attach to the Job 105 | jobChainCodeToCall := t.GetJobChaincodeToCall() 106 | funcOfJobChaincode := "addTX" 107 | invokeArgsOfJobChaincode := util.ToChaincodeArgs(funcOfJobChaincode, TXInfoJsonType.JobID, TXInfoJsonType.TxID) 108 | response1, err := stub.InvokeChaincode(jobChainCodeToCall, invokeArgsOfJobChaincode) 109 | if err != nil { 110 | errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error()) 111 | fmt.Printf(errStr) 112 | return nil, errors.New(errStr) 113 | } 114 | fmt.Printf("Invoke chaincode successful. Got response %s", string(response1)) 115 | 116 | //addTotalApplied 117 | funcOfJobChaincode3 := "addTotalApplied" 118 | invokeArgsOfJobChaincode3 := util.ToChaincodeArgs(funcOfJobChaincode3, TXInfoJsonType.JobID) 119 | response3, err := stub.InvokeChaincode(jobChainCodeToCall, invokeArgsOfJobChaincode3) 120 | if err != nil { 121 | errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error()) 122 | fmt.Printf(errStr) 123 | return nil, errors.New(errStr) 124 | } 125 | fmt.Printf("Invoke chaincode successful. Got response %s", string(response3)) 126 | 127 | //attach the TxID to related student 128 | //invoke UserInfo chaincode to add this TxID attach to the student 129 | userChainCodeToCall := t.GetUserChaincodeToCall() 130 | funcOfUserChaincode := "addTX" 131 | invokeArgsOfUserChaincode := util.ToChaincodeArgs(funcOfUserChaincode, TXInfoJsonType.UserID, TXInfoJsonType.TxID) 132 | response2, err := stub.InvokeChaincode(userChainCodeToCall, invokeArgsOfUserChaincode) 133 | if err != nil { 134 | errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error()) 135 | fmt.Printf(errStr) 136 | return nil, errors.New(errStr) 137 | } 138 | fmt.Printf("Invoke chaincode successful. Got response %s", string(response2)) 139 | 140 | //auto check 141 | // Query User`s credit score 142 | f := "queryCurrentCreditScore" 143 | queryArgs := util.ToChaincodeArgs(f, TXInfoJsonType.UserID) 144 | response, err := stub.QueryChaincode(userChainCodeToCall, queryArgs) 145 | if err != nil { 146 | errStr := fmt.Sprintf("Failed to query chaincode. Got error: %s", err.Error()) 147 | fmt.Printf(errStr) 148 | return nil, errors.New(errStr) 149 | } 150 | Score, err := strconv.Atoi(string(response)) 151 | if err != nil { 152 | errStr := fmt.Sprintf("Error retrieving state from ledger for queried chaincode: %s", err.Error()) 153 | fmt.Printf(errStr) 154 | return nil, errors.New(errStr) 155 | } 156 | if Score > 8 { 157 | TXInfoJsonType.Status = "已通过审核待评价" 158 | //addTotalHired 159 | invokeArgsOfJobChaincode5 := util.ToChaincodeArgs("addTotalHired", TXInfoJsonType.JobID) 160 | response5, err := stub.InvokeChaincode(jobChainCodeToCall, invokeArgsOfJobChaincode5) 161 | if err != nil { 162 | errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error()) 163 | fmt.Printf(errStr) 164 | return nil, errors.New(errStr) 165 | } 166 | fmt.Printf("Invoke chaincode successful. Got response %s", string(response5)) 167 | } else { 168 | TXInfoJsonType.Status = "未通过自动审核" 169 | //addTotalWaitCheck 170 | invokeArgsOfJobChaincode4 := util.ToChaincodeArgs("addTotalWaitCheck", TXInfoJsonType.JobID, "1") 171 | response4, err := stub.InvokeChaincode(jobChainCodeToCall, invokeArgsOfJobChaincode4) 172 | if err != nil { 173 | errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error()) 174 | fmt.Printf(errStr) 175 | return nil, errors.New(errStr) 176 | } 177 | fmt.Printf("Invoke chaincode successful. Got response %s", string(response4)) 178 | } 179 | 180 | // put the new TxInfo into state 181 | a, err := json.Marshal(TXInfoJsonType) 182 | if err != nil { 183 | return nil, err 184 | } 185 | // put the new score into state 186 | err = stub.PutState(TxID, a) 187 | if err != nil { 188 | return nil, errors.New("Failed to putstate") 189 | } 190 | 191 | return nil, nil 192 | } 193 | 194 | // ============================================================================================================================ 195 | // ArtificialCheck function is used to check this application when auto check not passed by agency 196 | // 2 input 197 | // "TxID","Result(1:通过;2:未通过)" 198 | // ============================================================================================================================ 199 | func (t *SimpleChaincode) ArtificialCheck(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 200 | var err error 201 | if len(args) != 2 { 202 | return nil, errors.New("Incorrect number of arguments. Expecting 2. ") 203 | } 204 | TxID := args[0] 205 | Result, _ := strconv.Atoi(args[1]) 206 | TxInfo, err := stub.GetState(TxID) 207 | 208 | //test if the TX has been existed 209 | if err != nil { 210 | return nil, errors.New("The TX never been exited") 211 | } 212 | if TxInfo == nil { 213 | return nil, errors.New("The TX`s information is empty!") 214 | } 215 | 216 | var TXInfoJsonType TXInfoStruct //json type to accept the TxInfo from state 217 | 218 | err = json.Unmarshal(TxInfo, &TXInfoJsonType) 219 | if err != nil { 220 | fmt.Println("error:", err) 221 | } 222 | 223 | if strings.EqualFold(TXInfoJsonType.Status, "未通过自动审核") { 224 | if Result == 1 { 225 | TXInfoJsonType.Status = "已通过审核待评价" 226 | //addTotalHired 227 | jobChainCodeToCall := t.GetJobChaincodeToCall() 228 | invokeArgsOfJobChaincode9 := util.ToChaincodeArgs("addTotalHired", TXInfoJsonType.JobID) 229 | response9, err := stub.InvokeChaincode(jobChainCodeToCall, invokeArgsOfJobChaincode9) 230 | if err != nil { 231 | errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error()) 232 | fmt.Printf(errStr) 233 | return nil, errors.New(errStr) 234 | } 235 | fmt.Printf("Invoke chaincode successful. Got response %s", string(response9)) 236 | 237 | } else { 238 | TXInfoJsonType.Status = "未通过审核,已回绝" 239 | } 240 | //addTotalWaitCheck 241 | jobChainCodeToCall := t.GetJobChaincodeToCall() 242 | invokeArgsOfJobChaincode6 := util.ToChaincodeArgs("addTotalWaitCheck", TXInfoJsonType.JobID, "-1") 243 | response6, err := stub.InvokeChaincode(jobChainCodeToCall, invokeArgsOfJobChaincode6) 244 | if err != nil { 245 | errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error()) 246 | fmt.Printf(errStr) 247 | return nil, errors.New(errStr) 248 | } 249 | fmt.Printf("Invoke chaincode successful. Got response %s", string(response6)) 250 | } else { 251 | return nil, errors.New("Incorrect stage of status. Expecting 未通过自动审核. ") 252 | } 253 | 254 | // put the new TxInfo into state 255 | a, err := json.Marshal(TXInfoJsonType) 256 | if err != nil { 257 | return nil, err 258 | } 259 | // put the new score into state 260 | err = stub.PutState(TxID, a) 261 | if err != nil { 262 | return nil, errors.New("Failed to putstate") 263 | } 264 | 265 | return nil, nil 266 | } 267 | 268 | // ============================================================================================================================ 269 | // Evaluate function is used to evaluate each other by student and agancy 270 | // 3 input 271 | // "TxID","UserID","Score" 272 | // ============================================================================================================================ 273 | func (t *SimpleChaincode) Evaluate(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 274 | var err error 275 | if len(args) != 3 { 276 | return nil, errors.New("Incorrect number of arguments. Expecting 3. ") 277 | } 278 | TxID := args[0] 279 | UserID := args[1] 280 | Score := args[2] 281 | 282 | TxInfo, err := stub.GetState(TxID) 283 | 284 | //test if the TX has been existed 285 | if err != nil { 286 | return nil, errors.New("The TX never been exited") 287 | } 288 | if TxInfo == nil { 289 | return nil, errors.New("The TX`s information is empty!") 290 | } 291 | 292 | var TXInfoJsonType TXInfoStruct //json type to accept the TxInfo from state 293 | 294 | err = json.Unmarshal(TxInfo, &TXInfoJsonType) 295 | if err != nil { 296 | fmt.Println("error:", err) 297 | } 298 | 299 | if strings.EqualFold(TXInfoJsonType.UserID, UserID) { 300 | TXInfoJsonType.AgencyScore = Score 301 | } else { 302 | TXInfoJsonType.StuScore = Score 303 | } 304 | 305 | f10 := "creditScoreEdit" 306 | invokeArgs10 := util.ToChaincodeArgs(f10, UserID, Score) 307 | response10, err := stub.InvokeChaincode(t.GetUserChaincodeToCall(), invokeArgs10) 308 | if err != nil { 309 | errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error()) 310 | fmt.Printf(errStr) 311 | return nil, errors.New(errStr) 312 | } 313 | 314 | fmt.Printf("Invoke chaincode successful. Got response %s", string(response10)) 315 | 316 | if len([]byte(TXInfoJsonType.StuScore)) != 0 && len([]byte(TXInfoJsonType.AgencyScore)) != 0 { 317 | StudentScore, _ := strconv.Atoi(TXInfoJsonType.StuScore) 318 | if StudentScore >= 8 { 319 | // Query agency`s ID 320 | f := "queryAgencyID" 321 | queryArgs := util.ToChaincodeArgs(f, TXInfoJsonType.JobID) 322 | AgencyID, err := stub.QueryChaincode(t.GetJobChaincodeToCall(), queryArgs) 323 | if err != nil { 324 | errStr := fmt.Sprintf("Failed to query chaincode. Got error: %s", err.Error()) 325 | fmt.Printf(errStr) 326 | return nil, errors.New(errStr) 327 | } 328 | // Query salary 329 | f1 := "querySalary" 330 | queryArgs1 := util.ToChaincodeArgs(f1, TXInfoJsonType.JobID) 331 | Salary, err := stub.QueryChaincode(t.GetJobChaincodeToCall(), queryArgs1) 332 | if err != nil { 333 | errStr := fmt.Sprintf("Failed to query chaincode. Got error: %s", err.Error()) 334 | fmt.Printf(errStr) 335 | return nil, errors.New(errStr) 336 | } 337 | 338 | f2 := "autoSettle" 339 | invokeArgs2 := util.ToChaincodeArgs(f2, TXInfoJsonType.UserID, string(AgencyID), string(Salary)) 340 | response2, err := stub.InvokeChaincode(t.GetUserChaincodeToCall(), invokeArgs2) 341 | if err != nil { 342 | errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error()) 343 | fmt.Printf(errStr) 344 | return nil, errors.New(errStr) 345 | } 346 | 347 | fmt.Printf("Invoke chaincode successful. Got response %s", string(response2)) 348 | 349 | TXInfoJsonType.Status = "已结算" 350 | //addTotalSettled 351 | jobChainCodeToCall := t.GetJobChaincodeToCall() 352 | invokeArgsOfJobChaincode7 := util.ToChaincodeArgs("addTotalSettled", TXInfoJsonType.JobID) 353 | response7, err := stub.InvokeChaincode(jobChainCodeToCall, invokeArgsOfJobChaincode7) 354 | if err != nil { 355 | errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", err.Error()) 356 | fmt.Printf(errStr) 357 | return nil, errors.New(errStr) 358 | } 359 | fmt.Printf("Invoke chaincode successful. Got response %s", string(response7)) 360 | } else { 361 | TXInfoJsonType.Status = "已评价未通过自动结算" 362 | } 363 | } else { 364 | // put the new TxInfo into state 365 | a, err := json.Marshal(TXInfoJsonType) 366 | if err != nil { 367 | return nil, err 368 | } 369 | // put the new score into state 370 | err = stub.PutState(TxID, a) 371 | if err != nil { 372 | return nil, errors.New("Failed to putstate") 373 | } 374 | return nil, nil 375 | } 376 | 377 | // put the new TxInfo into state 378 | a, err := json.Marshal(TXInfoJsonType) 379 | if err != nil { 380 | return nil, err 381 | } 382 | // put the new score into state 383 | err = stub.PutState(TxID, a) 384 | if err != nil { 385 | return nil, errors.New("Failed to putstate") 386 | } 387 | return nil, nil 388 | 389 | } 390 | 391 | // ============================================================================================================================ 392 | // Query function is the entry point for Queries 393 | // ============================================================================================================================ 394 | func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { 395 | 396 | if function == "queryTxInfo" { 397 | return t.QueryTxInfo(stub, args) 398 | } 399 | 400 | return nil, errors.New("failed to query") 401 | 402 | } 403 | 404 | // ============================================================================================================================ 405 | // QueryTxInfo function is used to query the Tx`s information. 406 | // 1 input 407 | // "TxID" 408 | // ============================================================================================================================ 409 | func (t *SimpleChaincode) QueryTxInfo(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 410 | if len(args) != 1 { 411 | return nil, errors.New("Incorrect number of arguments. Expecting 1 ") 412 | } 413 | TxID := args[0] 414 | 415 | // Get the state from the ledger 416 | TxInfo, err := stub.GetState(TxID) 417 | if err != nil { 418 | jsonResp := "{\"Error\":\"Failed to get state for " + TxID + "\"}" 419 | return nil, errors.New(jsonResp) 420 | } 421 | 422 | if TxInfo == nil { 423 | jsonResp := "{\"Error\":\"Nil content for " + TxID + "\"}" 424 | return nil, errors.New(jsonResp) 425 | } 426 | 427 | return TxInfo, nil 428 | } 429 | 430 | func main() { 431 | err := shim.Start(new(SimpleChaincode)) 432 | if err != nil { 433 | fmt.Printf("Error starting Simple chaincode: %s", err) 434 | } 435 | } 436 | -------------------------------------------------------------------------------- /chaincode/UserInfo/UserInfo.go: -------------------------------------------------------------------------------- 1 | // ============================================================================================================================ 2 | // 本智能合约用于用户信息管理 3 | // 功能包括:个人信息的增、删、改、查,信用积分的变更和查询,账户余额的变更和查询,兼职信息的添加 4 | // ============================================================================================================================ 5 | 6 | package main 7 | 8 | import ( 9 | "encoding/json" 10 | "errors" 11 | "fmt" 12 | "github.com/hyperledger/fabric/core/chaincode/shim" 13 | "strconv" 14 | ) 15 | 16 | type SimpleChaincode struct { 17 | } 18 | 19 | // ============================================================================================================================ 20 | // UserInfo struct 21 | // ============================================================================================================================ 22 | type UserInfoStruct struct { 23 | UserInfo UserStaticInfoStruct 24 | CreditScore CreditScoreStruct 25 | Balance string 26 | Jobs []string 27 | } 28 | 29 | // ============================================================================================================================ 30 | // UserStaticInfo struct 31 | // ============================================================================================================================ 32 | type UserStaticInfoStruct struct { 33 | UserID string 34 | Gender string 35 | School string 36 | StuID string 37 | Tele string 38 | AgencyName string 39 | Role string 40 | Username string 41 | BCID string 42 | Password string 43 | RealName string 44 | Status string 45 | } 46 | 47 | // ============================================================================================================================ 48 | // CreditScore struct 49 | // ============================================================================================================================ 50 | type CreditScoreStruct struct { 51 | CurrentCreditScore string 52 | TotalCreditScore string 53 | Ratetimes string 54 | } 55 | 56 | // ============================================================================================================================ 57 | // Init function 58 | // ============================================================================================================================ 59 | 60 | func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { 61 | return nil, nil 62 | } 63 | 64 | // ============================================================================================================================ 65 | // Invoke function is the entry point for Invocations 66 | // ============================================================================================================================ 67 | func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { 68 | 69 | // Handle different functions 70 | if function == "init" { 71 | return t.Init(stub, "init", args) 72 | } else if function == "add" { //add a new user 73 | return t.Add(stub, args) 74 | } else if function == "delete" { //deletes an user from its state 75 | return t.Delete(stub, args) 76 | } else if function == "edit" { //change the infor of the user 77 | return t.Edit(stub, args) 78 | } else if function == "creditScoreEdit" { // change the creditScore of the user 79 | return t.CreditScoreEdit(stub, args) 80 | } else if function == "addTX" { //add a new TX 81 | return t.AddTX(stub, args) 82 | } else if function == "autoSettle" { 83 | return t.AutoSettle(stub, args) 84 | } 85 | 86 | return nil, errors.New("Received unknown function invocation") 87 | } 88 | 89 | // ============================================================================================================================ 90 | // Add function is used for adding a new user 91 | // 2 input 92 | // "UserID","UserInfo" 93 | // ============================================================================================================================ 94 | func (t *SimpleChaincode) Add(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 95 | var err error 96 | if len(args) != 2 { 97 | return nil, errors.New("Incorrect number of arguments. Expecting 2. ") 98 | } 99 | UserID := args[0] 100 | UserInfo := args[1] 101 | UserTest, _ := stub.GetState(UserID) 102 | 103 | //test if the user has been existed 104 | if UserTest != nil { 105 | return nil, errors.New("the user is existed") 106 | } 107 | 108 | // add the user 109 | err = stub.PutState(UserID, []byte(UserInfo)) 110 | if err != nil { 111 | return nil, errors.New("Failed to add the user") 112 | } 113 | 114 | return nil, nil 115 | } 116 | 117 | // ============================================================================================================================ 118 | // Delete function is used for deleting a user 119 | // 1 input 120 | // "UserID" 121 | // ============================================================================================================================ 122 | func (t *SimpleChaincode) Delete(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 123 | var err error 124 | if len(args) != 1 { 125 | return nil, errors.New("Incorrect number of arguments. Expecting 1. ") 126 | } 127 | UserID := args[0] 128 | UserInfo, err := stub.GetState(UserID) 129 | 130 | //test if the user has been existed 131 | if err != nil { 132 | return nil, errors.New("The user never been exited") 133 | } 134 | 135 | if UserInfo == nil { 136 | return nil, errors.New("The user`s information is empty!") 137 | } 138 | 139 | err = stub.DelState(UserID) //remove the key from chaincode state 140 | if err != nil { 141 | return nil, errors.New("Failed to delete the user. ") 142 | } 143 | 144 | return nil, nil 145 | } 146 | 147 | // ============================================================================================================================ 148 | // Edit function is used for changing the user's info 149 | // 2 input 150 | // "UserID","NewUserInfo" 151 | // ============================================================================================================================ 152 | func (t *SimpleChaincode) Edit(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 153 | var err error 154 | if len(args) != 2 { 155 | return nil, errors.New("Incorrect number of arguments. Expecting 2. ") 156 | } 157 | UserID := args[0] 158 | NewUserInfo := args[1] 159 | OldUserInfo, err := stub.GetState(UserID) 160 | 161 | //test if the user has been existed 162 | if err != nil { 163 | return nil, errors.New("The user never been exited") 164 | } 165 | 166 | if OldUserInfo == nil { 167 | return nil, errors.New("The user`s information is empty!") 168 | } 169 | 170 | // edit the user 171 | err = stub.PutState(UserID, []byte(NewUserInfo)) 172 | if err != nil { 173 | return nil, errors.New("Failed to edit the user") 174 | } 175 | 176 | return nil, nil 177 | } 178 | 179 | // ============================================================================================================================ 180 | // CreditScoreEdit function is used for change the account's credit score 181 | // 2 input 182 | // "UserID","NewScoreFromOthersNow" 183 | // ============================================================================================================================ 184 | func (t *SimpleChaincode) CreditScoreEdit(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 185 | var err error 186 | if len(args) != 2 { 187 | return nil, errors.New("Incorrect number of arguments. Expecting 2. ") 188 | } 189 | UserID := args[0] 190 | NewScoreFromOthersNow, _ := strconv.Atoi(args[1]) 191 | UserInfo, err := stub.GetState(UserID) 192 | 193 | //test if the user has been existed 194 | if err != nil { 195 | return nil, errors.New("The user never been exited") 196 | } 197 | if UserInfo == nil { 198 | return nil, errors.New("The user`s information is empty!") 199 | } 200 | 201 | var UserInfoJsonType UserInfoStruct //json type to accept the UserInfo from state 202 | 203 | err = json.Unmarshal(UserInfo, &UserInfoJsonType) 204 | if err != nil { 205 | fmt.Println("error:", err) 206 | } 207 | 208 | var TotalScore int 209 | var TotalTimes int 210 | var CurrentScore int 211 | 212 | TotalScore, _ = strconv.Atoi(string(UserInfoJsonType.CreditScore.TotalCreditScore)) 213 | TotalTimes, _ = strconv.Atoi(string(UserInfoJsonType.CreditScore.Ratetimes)) 214 | 215 | TotalScore += NewScoreFromOthersNow 216 | TotalTimes++ 217 | CurrentScore = TotalScore / TotalTimes 218 | 219 | UserInfoJsonType.CreditScore.TotalCreditScore = strconv.Itoa(TotalScore) 220 | UserInfoJsonType.CreditScore.Ratetimes = strconv.Itoa(TotalTimes) 221 | UserInfoJsonType.CreditScore.CurrentCreditScore = strconv.Itoa(CurrentScore) 222 | 223 | // translate struct into json 224 | NewUserInfo, err := json.Marshal(UserInfoJsonType) 225 | if err != nil { 226 | return nil, err 227 | } 228 | // put the new score into state 229 | err = stub.PutState(UserID, NewUserInfo) 230 | if err != nil { 231 | return nil, errors.New("Failed to putstate") 232 | } 233 | 234 | return nil, nil 235 | } 236 | 237 | // ============================================================================================================================ 238 | // AddTX function is used to add TXID for the user 239 | // 2 input 240 | // "UserID","TXID" 241 | // ============================================================================================================================ 242 | func (t *SimpleChaincode) AddTX(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 243 | var err error 244 | if len(args) != 2 { 245 | return nil, errors.New("Incorrect number of arguments. Expecting 2. ") 246 | } 247 | UserID := args[0] 248 | TXID := args[1] 249 | UserInfo, err := stub.GetState(UserID) 250 | 251 | //test if the user has been existed 252 | if err != nil { 253 | return nil, errors.New("The user never been exited") 254 | } 255 | if UserInfo == nil { 256 | return nil, errors.New("The user`s information is empty!") 257 | } 258 | 259 | var UserInfoJsonType UserInfoStruct //json type to accept the UserInfo from state 260 | 261 | err = json.Unmarshal(UserInfo, &UserInfoJsonType) 262 | if err != nil { 263 | fmt.Println("error:", err) 264 | } 265 | 266 | UserInfoJsonType.Jobs = append(UserInfoJsonType.Jobs, TXID) 267 | 268 | // translate struct into json 269 | NewUserInfo, err := json.Marshal(UserInfoJsonType) 270 | if err != nil { 271 | return nil, err 272 | } 273 | // put the new score into state 274 | err = stub.PutState(UserID, NewUserInfo) 275 | if err != nil { 276 | return nil, errors.New("Failed to putstate") 277 | } 278 | 279 | return nil, nil 280 | } 281 | 282 | // ============================================================================================================================ 283 | // AutoSettle function is used to change the balance of user 284 | // 3 input 285 | // "StuID","AgencyID","Salary" 286 | // ============================================================================================================================ 287 | func (t *SimpleChaincode) AutoSettle(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 288 | var err error 289 | if len(args) != 3 { 290 | return nil, errors.New("Incorrect number of arguments. Expecting 3. ") 291 | } 292 | StuID := args[0] 293 | AgencyID := args[1] 294 | Salary, _ := strconv.Atoi(args[2]) 295 | StuInfo, err := stub.GetState(StuID) 296 | 297 | //test if the student has been existed 298 | if err != nil { 299 | return nil, errors.New("The student never been exited") 300 | } 301 | if StuInfo == nil { 302 | return nil, errors.New("The student`s information is empty!") 303 | } 304 | 305 | var UserInfoJsonTypeOfStu UserInfoStruct //json type to accept the UserInfo from state 306 | 307 | err = json.Unmarshal(StuInfo, &UserInfoJsonTypeOfStu) 308 | if err != nil { 309 | fmt.Println("error:", err) 310 | } 311 | 312 | OldBalanceOfStu, _ := strconv.Atoi(string(UserInfoJsonTypeOfStu.Balance)) 313 | NewBalanceOfStu := OldBalanceOfStu + Salary 314 | UserInfoJsonTypeOfStu.Balance = strconv.Itoa(NewBalanceOfStu) 315 | 316 | // translate struct into json 317 | NewStuInfo, err := json.Marshal(UserInfoJsonTypeOfStu) 318 | if err != nil { 319 | return nil, err 320 | } 321 | // put the new score into state 322 | err = stub.PutState(StuID, NewStuInfo) 323 | if err != nil { 324 | return nil, errors.New("Failed to putstate") 325 | } 326 | 327 | AgencyInfo, err := stub.GetState(AgencyID) 328 | 329 | //test if the agency has been existed 330 | if err != nil { 331 | return nil, errors.New("The agency never been exited") 332 | } 333 | if AgencyInfo == nil { 334 | return nil, errors.New("The agency`s information is empty!") 335 | } 336 | 337 | var UserInfoJsonTypeOfAgency UserInfoStruct //json type to accept the UserInfo from state 338 | 339 | err = json.Unmarshal(AgencyInfo, &UserInfoJsonTypeOfAgency) 340 | if err != nil { 341 | fmt.Println("error:", err) 342 | } 343 | 344 | OldBalanceOfAgency, _ := strconv.Atoi(string(UserInfoJsonTypeOfAgency.Balance)) 345 | NewBalanceOfAgency := OldBalanceOfAgency - Salary 346 | UserInfoJsonTypeOfAgency.Balance = strconv.Itoa(NewBalanceOfAgency) 347 | 348 | // translate struct into json 349 | NewAgencyInfo, err := json.Marshal(UserInfoJsonTypeOfAgency) 350 | if err != nil { 351 | return nil, err 352 | } 353 | // put the new score into state 354 | err = stub.PutState(AgencyID, NewAgencyInfo) 355 | if err != nil { 356 | return nil, errors.New("Failed to putstate") 357 | } 358 | 359 | return nil, nil 360 | } 361 | 362 | // ============================================================================================================================ 363 | // Query function is the entry point for Queries 364 | // ============================================================================================================================ 365 | func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) { 366 | 367 | if function == "queryCurrentCreditScore" { 368 | return t.QueryCurrentCreditScore(stub, args) 369 | } else if function == "queryUserInfo" { // reply if the account is existed 370 | return t.QueryUserInfo(stub, args) 371 | } 372 | 373 | return nil, errors.New("No this function name, failed to query") 374 | 375 | } 376 | 377 | // ============================================================================================================================ 378 | // QueryCurrentCreditScore function is used to query the user`s current credit score. 379 | // 1 input 380 | // "UserID" 381 | // ============================================================================================================================ 382 | func (t *SimpleChaincode) QueryCurrentCreditScore(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 383 | var err error 384 | if len(args) != 1 { 385 | return nil, errors.New("Incorrect number of arguments. Expecting 1 ") 386 | } 387 | UserID := args[0] 388 | UserInfo, err := stub.GetState(UserID) 389 | 390 | //test if the user has been existed 391 | if err != nil { 392 | return nil, errors.New("The user never been exited") 393 | } 394 | if UserInfo == nil { 395 | return nil, errors.New("The user`s information is empty!") 396 | } 397 | 398 | var UserInfoJsonType UserInfoStruct //json type to accept the UserInfo from state 399 | 400 | err = json.Unmarshal(UserInfo, &UserInfoJsonType) 401 | if err != nil { 402 | fmt.Println("error:", err) 403 | } 404 | 405 | return []byte(UserInfoJsonType.CreditScore.CurrentCreditScore), nil 406 | } 407 | 408 | // ============================================================================================================================ 409 | // QueryUserInfo function is used to return the whole information of the user. 410 | // 1 input 411 | // "UserID" 412 | // ============================================================================================================================ 413 | func (t *SimpleChaincode) QueryUserInfo(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) { 414 | if len(args) != 1 { 415 | return nil, errors.New("Incorrect number of arguments. Expecting 1 ") 416 | } 417 | UserID := args[0] 418 | 419 | // Get the state from the ledger 420 | UserInfo, err := stub.GetState(UserID) 421 | if err != nil { 422 | jsonResp := "{\"Error\":\"Failed to get state for " + UserID + "\"}" 423 | return nil, errors.New(jsonResp) 424 | } 425 | 426 | if UserInfo == nil { 427 | jsonResp := "{\"Error\":\"Nil content for " + UserID + "\"}" 428 | return nil, errors.New(jsonResp) 429 | } 430 | 431 | return UserInfo, nil 432 | } 433 | 434 | func main() { 435 | err := shim.Start(new(SimpleChaincode)) 436 | if err != nil { 437 | fmt.Printf("Error starting Simple chaincode: %s", err) 438 | } 439 | } 440 | -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | 3 | # uwsgi 启动时所使用的地址与端口 4 | socket = 127.0.0.1:8001 5 | 6 | # 指向网站目录 7 | chdir = /app 8 | 9 | # python 启动程序文件 10 | wsgi-file = manage.py 11 | 12 | # python 程序内用以启动的 application 变量名 13 | # callable=app 这个 app 是 manage.py 程序文件内的一个变量,这个变量的类型是 Flask的 application 类 。 14 | callable = app 15 | 16 | # 处理器数 17 | processes = 1 18 | 19 | # 线程数 20 | threads = 4 21 | 22 | #状态检测地址 23 | stats = 127.0.0.1:9191 24 | 25 | buffer-size=32768 26 | 27 | daemonize = /app/logs/uwsgi.log -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | DEBUG = False 6 | SQLALCHEMY_TRACK_MODIFICATIONS = True 7 | 8 | 9 | def main(): 10 | pass 11 | 12 | 13 | if __name__ == '__main__': 14 | main() 15 | -------------------------------------------------------------------------------- /debug-start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "start redis" 4 | # start redis 5 | redis-server --daemonize yes 6 | 7 | #echo '' 8 | #echo "start queue" 9 | #echo "start message queue" 10 | #nohup python /app/deamonqueue.py & 11 | #echo "start match queue" 12 | #nohup python /app/queue/cny2btcQ.py & 13 | #nohup python /app/queue/cny2goldQ.py & 14 | #nohup python /app/queue/gold2btcQ.py & 15 | 16 | echo '' 17 | echo "start mongo" 18 | # start mongodb 19 | mongod --fork --logpath /var/log/mongod.log 20 | 21 | echo '' 22 | echo "start node" 23 | # TODO 24 | 25 | echo '' 26 | echo "start server" 27 | # start server 28 | python manage.py runserver -h 0.0.0.0 29 | -------------------------------------------------------------------------------- /frontend/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBD-Forum/N0020-Tongjia/ab6550b910559daf380aeb6b4dbd4df46ebbfdd8/frontend/.gitkeep -------------------------------------------------------------------------------- /frontend/install_frontend.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | init=$1 4 | echo $init 5 | 6 | cd `dirname $0` 7 | 8 | dir_root='PartTimePlatform-frontend' 9 | dir_cur=`pwd` 10 | 11 | dir_cur=$dir_cur"/"$dir_root 12 | 13 | echo "current dir: "$dir_cur 14 | cd $dir_cur 15 | 16 | # install dependecies 17 | echo "npm install" 18 | npm install 19 | # pacakge to deploy 20 | echo "npm build" 21 | npm run build 22 | 23 | if [ "$init" == "init" ]; then 24 | echo 'init install http-server' 25 | # enter the root directory 26 | cd dist 27 | # install node http-server 28 | npm install -g http-server 29 | fi 30 | 31 | 32 | echo 'finish' -------------------------------------------------------------------------------- /frontend/npm-debug.log: -------------------------------------------------------------------------------- 1 | 0 info it worked if it ends with ok 2 | 1 verbose cli [ '/usr/bin/nodejs', '/usr/bin/npm', 'run', 'build' ] 3 | 2 info using npm@3.10.10 4 | 3 info using node@v6.10.2 5 | 4 verbose stack Error: ENOENT: no such file or directory, open '/app/frontend/package.json' 6 | 4 verbose stack at Error (native) 7 | 5 verbose cwd /app/frontend 8 | 6 error Linux 4.9.13-moby 9 | 7 error argv "/usr/bin/nodejs" "/usr/bin/npm" "run" "build" 10 | 8 error node v6.10.2 11 | 9 error npm v3.10.10 12 | 10 error path /app/frontend/package.json 13 | 11 error code ENOENT 14 | 12 error errno -2 15 | 13 error syscall open 16 | 14 error enoent ENOENT: no such file or directory, open '/app/frontend/package.json' 17 | 15 error enoent ENOENT: no such file or directory, open '/app/frontend/package.json' 18 | 15 error enoent This is most likely not a problem with npm itself 19 | 15 error enoent and is related to npm not being able to find a file. 20 | 16 verbose exit [ -2, true ] 21 | -------------------------------------------------------------------------------- /frontend/start_front_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd `dirname $0` 4 | 5 | dir_root='PartTimePlatform-frontend' 6 | dir_cur=`pwd` 7 | 8 | dir_cur=$dir_cur"/"$dir_root"/dist" 9 | 10 | echo "current dir: "$dir_cur 11 | cd $dir_cur 12 | 13 | # deploy 14 | hs -p 8080 -------------------------------------------------------------------------------- /instance/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | def main(): 6 | pass 7 | 8 | 9 | if __name__ == '__main__': 10 | main() 11 | -------------------------------------------------------------------------------- /instance/config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | # mysql 5 | 6 | DEBUG = True 7 | SECRET_KEY = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' 8 | 9 | GONGXIANGDANCHE_TOKEN = '' 10 | 11 | TRY_REQ = True 12 | 13 | REDIS_URL = "redis://:@localhost:6379/0" 14 | REDIS_QUEUE_KEY = "my_queue" 15 | 16 | MONGOALCHEMY_DATABASE = 'library' 17 | MONGOALCHEMY_SERVER_AUTH = False 18 | 19 | RUN_IN_PYTHON_SERVER = False # False for nginx server and True for command `python manage.py runserver -h 0.0.0.0` 20 | 21 | BLOCKCHAIN_USERINFO_URL = "https://a6377d73838047d39f8527f035520915-vp0.us.blockchain.ibm.com:5002/chaincode" 22 | BLOCKCHAIN_TX_URL = "https://a6377d73838047d39f8527f035520915-vp0.us.blockchain.ibm.com:5002/chaincode" 23 | BLOCKCHAIN_JOBINFO_URL = "https://a6377d73838047d39f8527f035520915-vp0.us.blockchain.ibm.com:5002/chaincode" 24 | 25 | BLOCKCHAIN_USERINFO_CHAINCODE_ID = "9d29747f0b642ed65f481fbc1132d518834b3099671ad5d86feb8609202197f26cefcca348942ce9facdbe8312b5d7ee5598a6d9522c34ae9755720c1176a598" 26 | BLOCKCHAIN_JOBINFO_CHAINCODE_ID = "7147861cb80f5447b0ee974bc917935cc8f65bd89a271095af7e0f7cb8184a7dccdbb93a43fce11d24c7532743c7d22c0fa68c6f6bbc29bb8a92f2e98b2d92ae" 27 | BLOCKCHAIN_TX_CHAINCODE_ID = "3e960549e21165e0a0a03087dc9745436644cb77876ec324949048f7486018cf71f92f30234358c487d7374a7e8ab57156bfec0a2df37cf864f4b2c126716ece" 28 | 29 | 30 | def main(): 31 | pass 32 | 33 | 34 | if __name__ == '__main__': 35 | main() 36 | -------------------------------------------------------------------------------- /logs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CBD-Forum/N0020-Tongjia/ab6550b910559daf380aeb6b4dbd4df46ebbfdd8/logs/.gitkeep -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | from flask.ext.script import Manager, Shell 5 | from app import app 6 | 7 | manager = Manager(app) 8 | 9 | 10 | def main(): 11 | pass 12 | 13 | 14 | def make_shell_context(): 15 | return dict(app=app) 16 | 17 | 18 | manager.add_command("shell", Shell(make_context=make_shell_context)) 19 | 20 | 21 | @manager.command 22 | def deploy(): 23 | """Run deployment tasks.""" 24 | pass 25 | 26 | 27 | if __name__ == '__main__': 28 | # app() 29 | manager.run() 30 | -------------------------------------------------------------------------------- /nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 8000; 3 | server_name 0.0.0.0; #公网地址 4 | 5 | location / { 6 | include uwsgi_params; 7 | uwsgi_pass 127.0.0.1:8001; # 指向uwsgi 所应用的内部地址,所有请求将转发给uwsgi 处理 8 | uwsgi_read_timeout 600; 9 | } 10 | 11 | #配置静态文件转发 12 | #location ~/static { 13 | # root /app/app/; 14 | #} 15 | 16 | ##配置静态文件转发 17 | #location ~.*(js|css|png|gif|jpg|mp3|ogg|ico)$ { 18 | # root /app/app/static; 19 | #} 20 | ##配置静态页面转发 21 | #location ~.*(html)$ { 22 | # root /app/app/static; 23 | #} 24 | 25 | #配置静态文件转发 26 | location ~.*(js|css|png|gif|jpg|jpeg|mp3|ogg|ico)$ { 27 | root /app/frontend/PartTimePlatform-frontend/dist; 28 | } 29 | #配置静态页面转发 30 | location ~.*(html)$ { 31 | root /app/frontend/PartTimePlatform-frontend/dist; 32 | } 33 | location ~/static { 34 | root /app/frontend/PartTimePlatform-frontend/dist; 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | 2 | user nginx; 3 | worker_processes 1; 4 | 5 | error_log /var/log/nginx/error.log warn; 6 | pid /var/run/nginx.pid; 7 | 8 | 9 | events { 10 | worker_connections 1024; 11 | } 12 | 13 | 14 | http { 15 | include /etc/nginx/mime.types; 16 | default_type application/octet-stream; 17 | 18 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 19 | '$status $body_bytes_sent "$http_referer" ' 20 | '"$http_user_agent" "$http_x_forwarded_for"'; 21 | 22 | access_log /var/log/nginx/access.log main; 23 | 24 | sendfile on; 25 | #tcp_nopush on; 26 | 27 | keepalive_timeout 65; 28 | 29 | #gzip on; 30 | 31 | include /etc/nginx/conf.d/*.conf; 32 | } 33 | # daemon off; -------------------------------------------------------------------------------- /redis-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export REDIS_VERSION=3.0.7 3 | export REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-3.0.7.tar.gz 4 | export REDIS_DOWNLOAD_SHA1=e56b4b7e033ae8dbf311f9191cf6fdf3ae974d1c 5 | 6 | wget -O redis.tar.gz "$REDIS_DOWNLOAD_URL" \ 7 | && echo "$REDIS_DOWNLOAD_SHA1 *redis.tar.gz" | sha1sum -c - \ 8 | && mkdir -p /usr/src/redis \ 9 | && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \ 10 | && rm redis.tar.gz \ 11 | && make -C /usr/src/redis \ 12 | && make -C /usr/src/redis install \ 13 | && rm -r /usr/src/redis 14 | 15 | redis-server --daemonize yes -------------------------------------------------------------------------------- /refresh_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # override nginx config 4 | cp nginx.conf /etc/nginx/conf.d/ 5 | 6 | # add related python libs 7 | pip install -r requirement.txt 8 | 9 | # refresh nodejs libs 10 | bash frontend/install_frontend.sh -------------------------------------------------------------------------------- /requirement.txt: -------------------------------------------------------------------------------- 1 | # Flask Framework 2 | Flask == 0.12 3 | 4 | # Flask Packages 5 | # Flask-SQLAlchemy>=2.0 6 | Flask-MongoAlchemy 7 | mongoengine 8 | flask-mongoengine 9 | Flask-Script 10 | flask-redis 11 | Flask-User==0.6.11 12 | Flask-WTF==0.13.1 13 | Flask-Login==0.4.0 14 | 15 | # hyperledger for python 16 | hyperledger 17 | ipaddress 18 | 19 | # others 20 | enum34 -------------------------------------------------------------------------------- /startserver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #cp nginx/nginx.conf /etc/nginx/nginx.conf 4 | cp nginx.conf /etc/nginx/conf.d/ 5 | # init file 6 | 7 | echo "start redis" 8 | # start redis 9 | redis-server --daemonize yes 10 | 11 | #echo "" 12 | #echo "===========" 13 | #echo "start queue" 14 | #echo "start message queue" 15 | #nohup python /app/deamonqueue.py & 16 | #echo "start match queue" 17 | #nohup python /app/queue/cny2btcQ.py & 18 | #nohup python /app/queue/cny2goldQ.py & 19 | #nohup python /app/queue/gold2btcQ.py & 20 | 21 | echo "" 22 | echo "===========" 23 | echo "start mongo" 24 | # start mongodb 25 | mongod --fork --logpath /var/log/mongod.log 26 | 27 | echo "" 28 | echo "===========" 29 | echo "start uwsgi" 30 | # start uwsgi 31 | uwsgi /app/config.ini 32 | 33 | echo "" 34 | echo "===========" 35 | echo "start nginx" 36 | # start server 37 | nginx 38 | 39 | #echo "" 40 | #echo "===========" 41 | #echo "start front-end server" 42 | #bash frontend/start_front_server.sh --------------------------------------------------------------------------------