├── .gitee
├── ISSUE_TEMPLATE.zh-CN.md
└── PULL_REQUEST_TEMPLATE.zh-CN.md
├── .gitignore
├── LICENSE
├── README.en.md
├── README.md
├── activate.bat
├── activate.sh
├── app
├── __init__.py
├── api
│ └── __init__.py
├── common
│ ├── __init__.py
│ ├── captcha.py
│ ├── mail.py
│ ├── mixin.py
│ ├── ml.py
│ ├── param.py
│ ├── result.py
│ ├── schema.py
│ ├── status.py
│ └── wrap.py
└── modules
│ ├── __init__.py
│ ├── admin
│ ├── __init__.py
│ ├── dao.py
│ ├── model.py
│ ├── param.py
│ ├── resource.py
│ └── schema.py
│ ├── adminroles
│ ├── __init__.py
│ ├── model.py
│ ├── param.py
│ ├── resource.py
│ └── schema.py
│ ├── attachments
│ ├── __init__.py
│ ├── dao.py
│ ├── model.py
│ ├── param.py
│ ├── resource.py
│ └── schema.py
│ ├── category
│ ├── __init__.py
│ ├── dao.py
│ ├── model.py
│ ├── param.py
│ ├── resource.py
│ └── schema.py
│ ├── configs
│ ├── __init__.py
│ ├── dao.py
│ ├── model.py
│ ├── param.py
│ ├── resource.py
│ └── schema.py
│ ├── iris
│ ├── __init__.py
│ ├── dao.py
│ ├── model.py
│ ├── param.py
│ ├── resource.py
│ └── schema.py
│ ├── logs
│ ├── __init__.py
│ ├── dao.py
│ ├── model.py
│ ├── param.py
│ ├── resource.py
│ └── schema.py
│ ├── notice_content
│ ├── __init__.py
│ ├── dao.py
│ ├── model.py
│ ├── param.py
│ ├── resource.py
│ └── schema.py
│ ├── notice_content_admin
│ ├── __init__.py
│ ├── dao.py
│ ├── model.py
│ ├── param.py
│ ├── resource.py
│ └── schema.py
│ ├── profiles
│ ├── __init__.py
│ ├── dao.py
│ ├── model.py
│ ├── param.py
│ ├── resource.py
│ └── schema.py
│ ├── resources
│ ├── __init__.py
│ ├── dao.py
│ ├── model.py
│ ├── param.py
│ ├── resource.py
│ └── schema.py
│ ├── roles
│ ├── __init__.py
│ ├── dao.py
│ ├── model.py
│ ├── param.py
│ ├── resource.py
│ └── schema.py
│ └── rolesresources
│ ├── __init__.py
│ ├── dao.py
│ ├── model.py
│ ├── param.py
│ ├── resource.py
│ └── schema.py
├── assets
└── img
│ └── baoai
│ ├── admin.png
│ ├── ai.png
│ ├── baoai_avatar_160.png
│ ├── baoai_favicon_16.png
│ ├── baoai_favicon_32.png
│ ├── favicon.ico
│ ├── know.png
│ ├── logo.png
│ ├── quant.png
│ ├── soft.jpg
│ ├── sys.png
│ └── web.png
├── config.py
├── db
├── baoai.db
└── baoai.sql
├── deploy
├── ReadME.md
├── baoai.ini
├── beat.ini
├── gunicorn_config.py
├── nginx.conf
└── worker.ini
├── flask_restplus
├── __about__.py
├── __init__.py
├── _http.py
├── api.py
├── apidoc.py
├── cors.py
├── errors.py
├── fields.py
├── inputs.py
├── marshalling.py
├── mask.py
├── model.py
├── namespace.py
├── postman.py
├── representations.py
├── reqparse.py
├── resource.py
├── static
│ ├── droid-sans.css
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── files
│ │ ├── .npmignore
│ │ ├── droid-sans-latin-400.woff
│ │ ├── droid-sans-latin-400.woff2
│ │ ├── droid-sans-latin-700.woff
│ │ └── droid-sans-latin-700.woff2
│ ├── swagger-ui-bundle.js
│ ├── swagger-ui-bundle.js.map
│ ├── swagger-ui-standalone-preset.js
│ ├── swagger-ui-standalone-preset.js.map
│ ├── swagger-ui.css
│ ├── swagger-ui.css.map
│ ├── swagger-ui.js
│ └── swagger-ui.js.map
├── swagger.py
├── templates
│ ├── swagger-ui-css.html
│ ├── swagger-ui-libs.html
│ └── swagger-ui.html
└── utils.py
├── flask_restplus_patched
├── __init__.py
├── _http.py
├── api.py
├── http_exceptions.py
├── model.py
├── namespace.py
├── parameters.py
├── resource.py
└── swagger.py
├── kill_python.sh
├── logging_config.py
├── manage.py
├── remote_debug.py
├── requirements.txt
├── requirements_talib.txt
├── run_baoai.bat
├── run_baoai.sh
├── run_www.bat
├── run_www.sh
├── static
├── ai
│ └── iris
│ │ ├── 3c099ad2-4ed1-11ea-a3e0-b42e9995d7c8.png
│ │ └── c988de40-5330-11ea-aa9b-b42e9995d7c8.png
└── uploads
│ └── 2020
│ ├── 01
│ ├── 02
│ │ └── e4a77d02199947d4b0066aa9bd4e8b57.jpg
│ └── 03
│ │ └── eff0930192824964b3dbc0a716c8c5a9.png
│ └── 02
│ └── 14
│ └── 4fcc3b62d0f94421b56226a691eeb2fd.png
├── www
├── __init__.py
├── modules
│ ├── __init__.py
│ ├── about
│ │ ├── __init__.py
│ │ ├── task.py
│ │ └── views.py
│ └── main
│ │ ├── __init__.py
│ │ ├── task.py
│ │ └── views.py
└── templates
│ ├── about
│ └── index.html
│ └── main
│ └── index.html
└── www_manage.py
/.gitee/ISSUE_TEMPLATE.zh-CN.md:
--------------------------------------------------------------------------------
1 | ### 该问题是怎么引起的?
2 |
3 |
4 |
5 | ### 重现步骤
6 |
7 |
8 |
9 | ### 报错信息
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md:
--------------------------------------------------------------------------------
1 | ### 相关的Issue
2 |
3 |
4 | ### 原因(目的、解决的问题等)
5 |
6 |
7 | ### 描述(做了什么,变更了什么)
8 |
9 |
10 | ### 测试用例
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/
2 |
3 | # Python
4 | *.py[cod]
5 | *.so
6 | *.egg
7 | *.egg-info
8 | dist/
9 | build/
10 | __pycache__/
11 |
12 | # pyvenv
13 | venv*/
14 |
15 |
16 | *.tar
17 | *.tar.gz
18 |
19 | *.sqlite
20 | migrations/
21 | .vscode/
22 |
23 | # Python
24 | *.py[cod]
25 | *.so
26 | *.egg
27 | *.egg-info
28 | dist/
29 | build/
30 | __pycache__/
31 |
32 | # pyvenv
33 | venv/
34 |
35 | *.tar
36 | *.tar.gz
37 |
38 | *.log
39 | migrations/
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BaoAI 小宝人工智能和量化系统
2 | 人工智能和量化从这开始
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 小宝人工智能和量化平台是简洁、直观、强大的前端和后端SPA开发框架,支持国际化,以模块为基础,让WEB应用、人工智能和量化系统开发更迅速、更简单。平台包含多个模块,主要包括基于角色的权限管理基础平台(用户、角色、权限、日志、附件、配置参数、分类管理)、通知模块、自动代码产生模块、任务系统模块、内容管理系统模块、网站模块、电子手册模块、人工智能模块、图像识别模块,人脸识别模块,金融数据采集模块,大数据模块,量化交易模块等。
20 |
21 | ## 功能特点:
22 |
23 | + 超10万行代码
24 | + 平台模块化,易于开发扩展
25 | + 前端兼容多种浏览器
26 | + 兼容性好,跨平台,响应式设计
27 | + 平台二次开发学习曲线低,易上手
28 | + 国际化
29 | + 前后端代码分离
30 | + 基于H5的单页面应用(SPA)
31 | + 自动代码产生器
32 | + 自动产生API文档及测试界面
33 | + 支持多数据库和数据迁移
34 | + 强大的富文本编辑
35 | + 人工智能
36 | + 大数据网络爬虫
37 | + 金融数据采集模块
38 | + 量化分析
39 | + 完善的开发和部署工具和方案
40 |
41 | ## 下载源码
42 |
43 | BaoAI前后端分离框构,包含有前端项目和后端项目
44 |
45 | + 前端项目源码: [BaoAIFront](https://github.com/yuanbaonet/baoaifront)
46 |
47 | + 后端项目源码: [BaoAIBack](https://github.com/yuanbaonet/baoaiback)
48 |
49 | ## 文档
50 |
51 | + 手册
52 | + [BaoAI 开发手册](http://www.baoai.co/web/book?id=50)
53 | + [BaoAI 后端开发手册](http://www.baoai.co/web/book?id=48)
54 |
55 | + API
56 | + 以开发模式运行后端项目后,即可加载,如:http://localhost:8000/api, 使用Swagger UI加载。
57 |
58 | + 模块扩展
59 | + [模块](http://www.baoai.co/web/book?id=88)
60 |
61 |
62 | ## 前端和后端开发工具
63 |
64 | [Visual Studio Code](http://code.visualstudio.com)
65 |
66 | 安装插件:
67 |
68 | `Chinese (Simplified) Language Pack for Visual Studio Code`
69 |
70 | `jshint`
71 |
72 | `Python`
73 |
74 | `Git history`
75 |
76 |
77 | ## 项目后端 BaoAIBack 安装步骤
78 |
79 | 需要 [Python 3.6](http://www.python.org)
80 |
81 | ```shell
82 | # 1. 创建虚拟环境
83 | # windows, 假设项目根路径:d:/baoai/BaoaiBack/
84 | cd d:/baoai/BaoaiBack
85 | mkdir venv
86 | cd venv
87 | python -m venv .
88 |
89 | # 运行虚拟环境
90 | d:/baoai/BaoaiBack/venv/Scripts/activate.bat
91 | cd d:/baoai/BaoaiBack
92 |
93 | # linux, 假设项目根路径:/baoai/BaoaiBack/
94 | cd /baoai/BaoaiBack
95 | mkdir venv
96 | cd venv
97 | python -m venv .
98 |
99 | # 运行虚拟环境
100 | source /baoai/BaoaiBack/venv/bin/activate
101 | cd /baoai/BaoaiBack
102 |
103 | # 2. 安装依赖库(必须处于虚拟环境)
104 | # windows 安装依赖库
105 | python -m pip install --upgrade pip
106 | pip install -r requirements.txt
107 | # 如果下载速度慢可以采用国内镜像
108 | pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
109 |
110 | # linux 安装依赖库
111 | python -m pip3 install --upgrade pip
112 | pip3 install -r requirements.txt
113 | # 如果下载速度慢可以采用国内镜像
114 | pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
115 |
116 | # 3. 运行 Restful 服务
117 | # windows
118 | run_baoai.bat
119 |
120 | # linux
121 | # 默认使用gunicorn做为wsgi
122 | chmod +x run_baoai.sh
123 | ./run_baoai.sh
124 |
125 | # 4. 运行 www 服务(Jinja模块)
126 | # windows
127 | run_www.bat
128 |
129 | # linux
130 | chmod +x run_www.sh
131 | ./run_www.sh
132 |
133 | # 常用功能
134 | # 清空缓存
135 | python manage.py clean
136 |
137 |
138 | ```
139 | ## 项目后端数据库
140 |
141 | 本项目支持绝大部门流行的关系数据库,包括:SQLite、MySQL、Postgres、Oracle、MS-SQL、SQLServer 和 Firebird。
142 |
143 | 已提供Sqlite数据库,和MySQL数据脚本文件。MySQL支持5.5及以上版本。
144 |
145 | 数据库转换无需修改代码,仅修改config.py中的SQLALCHEMY_DATABASE_URI即可。
146 |
147 | 默认使用sqlite数据库,优点是无需安装专门数据库软件,方便测试开发,生产部署请使用mysql或其它数据库软件。
148 |
149 | sqlite数据保存在 `db/baoai.db`,直接使用。
150 |
151 | mysql数据库脚本保存在 `db/baoai.mysql.sql`,需要新建数据库如baoai,然后导入脚本。
152 |
153 | 如果使用其他数据库,可以使用`Navicat Premium`工具菜单中的`数据传输`,进行不同数据库之前的数据迁移。
154 |
155 | 数据库相关操作:
156 | ```
157 | # 数据迁移服务
158 | # 初始化
159 | python manage.py db init
160 |
161 | # 模型迁移
162 | python manage.py db migrate
163 |
164 | # 数据库脚本更新(操作数据)
165 | python manage.py db upgrade
166 | ```
167 |
168 | ## 项目代码自动产生模块
169 |
170 | 使用自动代码产生模块,可以使字段、模型、生成数据库、前端代码、后端代码和权限配置一并可视化完成,一般项目可以零代码实现。
171 | 该部份主要包括三个扩展模块: 数据迁移模块、自动代码模型模块和自动代码产生模块
172 |
173 |
174 | ## BaoAI 小宝人工智能和量化平台系统架构
175 |
176 |
177 |
178 | ## BaoAI 小宝人工智能和量化平台知识体系
179 |
180 | 可用于各行业的前端和后端系统软件开发、CMS、人工智能、图像识别、人脸识别、大数据和量化投资领域等。前后端分离SPA架构,使用AngularJS/Bootstrap等前端框架实现响应式和SPA程序设计,后端主要使用Python语言,主要包括如下框架:flask提供web服务,Jinja2提供模板服务,Numpy、Pandas、Scikit-Learn、Tensorflow和Keras等实现人工智能服务,celery实现任务调度,scrapy提供网络爬虫,基于Backtrader的金融量化服务等。
181 |
182 |
183 |
184 | 基于BaoAI设计案例:
185 |
186 | 内容管理网站:
187 |
188 |
189 |
190 | 管理系统后台:
191 |
192 |
193 |
194 | 人工智能:
195 |
196 |
197 |
198 | 量化系统:
199 |
200 |
201 |
202 | ## 帮助
203 |
204 | + Email [703264459@qq.com](703264459@qq.com)
205 |
206 |
207 | ## 版权说明
208 |
209 | Apache2.0
210 |
211 | ## 版权说明
212 |
213 |
214 |
215 |
216 |
217 |
218 |
--------------------------------------------------------------------------------
/activate.bat:
--------------------------------------------------------------------------------
1 | venv\Scripts\activate.bat
--------------------------------------------------------------------------------
/activate.sh:
--------------------------------------------------------------------------------
1 | source venv/bin/activate
--------------------------------------------------------------------------------
/app/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 | from flask import Flask, Blueprint
3 | from flask_sqlalchemy import SQLAlchemy
4 | from flask_cors import CORS
5 | from config import config
6 | from celery import Celery
7 | import logging_config
8 |
9 | db = SQLAlchemy()
10 | Config = config[os.getenv('FLASK_CONFIG') or 'default']
11 | celery = None
12 |
13 | def create_app():
14 | app = Flask(__name__, static_url_path=Config.APP_STATIC_URL_PATH, static_folder=Config.STATIC_FOLDER)
15 | app.config.from_object(Config)
16 | db.init_app(app)
17 | db.app = app
18 |
19 | # 解决禁止跨域请求的问题
20 | if app.config['CORS_ENABLED']:
21 | CORS(app, supports_credentials=True)
22 |
23 | # init Celery # 初始化Celery
24 | # global celery
25 | # celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'], backend=app.config['CELERY_RESULT_BACKEND'])
26 | # celery.conf.update(app.config)
27 |
28 | # init modules # 初始化模块,将模块对应的命名空间增加到蓝图
29 | from . import modules
30 | modules.init_app(app)
31 |
32 | # register blueprint # 注册蓝图到应用
33 | from . import api
34 | api.init_api(app)
35 |
36 | return app # , celery
37 |
--------------------------------------------------------------------------------
/app/api/__init__.py:
--------------------------------------------------------------------------------
1 | from flask import Blueprint, current_app
2 | from flask_restplus_patched import Api
3 | from app import Config
4 | from flask_sqlalchemy import get_debug_queries
5 |
6 | api_blueprint = Blueprint("open_api", __name__, url_prefix=Config.APP_BLUE_PRINT_URL_PREFIX)
7 | api = Api(api_blueprint, version="1.0",
8 | prefix=Config.APP_API_VERSION, title="BaoAI", description="BaoAI Open Api Service")
9 |
10 | # 查询花费时间较慢的阀值,高于该值将记录flask日志
11 | @api_blueprint.after_app_request
12 | def after_request(response):
13 | for query in get_debug_queries():
14 | if query.duration >= Config.FLASK_SLOW_DB_QUERY_TIME :
15 | current_app.logger.warning('Slow query: %s\nParameters:%s\nDuration:%fs\nContext: %s\n' %(query.statement, query.parameters, query.duration, query.context))
16 | return response
17 |
18 | def init_api(app):
19 | app.register_blueprint(api_blueprint)
--------------------------------------------------------------------------------
/app/common/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/app/common/__init__.py
--------------------------------------------------------------------------------
/app/common/captcha.py:
--------------------------------------------------------------------------------
1 | import base64
2 | import io
3 | import random
4 | import string
5 | from PIL import Image, ImageFont, ImageDraw
6 |
7 | class CaptchaTool(object):
8 | """
9 | 生成图片验证码
10 | """
11 |
12 | def __init__(self, width=50, height=12):
13 |
14 | self.width = width
15 | self.height = height
16 | # 新图片对象
17 | self.im = Image.new('RGB', (width, height), 'white')
18 | # 字体
19 | self.font = ImageFont.load_default()
20 | # draw对象
21 | self.draw = ImageDraw.Draw(self.im)
22 |
23 | def draw_lines(self, num=3):
24 | """
25 | 划线
26 | """
27 | for num in range(num):
28 | x1 = random.randint(0, self.width / 2)
29 | y1 = random.randint(0, self.height / 2)
30 | x2 = random.randint(0, self.width)
31 | y2 = random.randint(self.height / 2, self.height)
32 | self.draw.line(((x1, y1), (x2, y2)), fill='black', width=1)
33 |
34 | def get_verify_code(self):
35 | """
36 | 生成验证码图形
37 | """
38 | # 设置随机4位数字验证码
39 | code = ''.join(random.sample(string.digits, 4))
40 | # 绘制字符串
41 | for item in range(4):
42 | self.draw.text((6 + random.randint(-3, 3) + 10 * item, 2 + random.randint(-2, 2)),
43 | text=code[item],
44 | fill=(random.randint(32, 127),
45 | random.randint(32, 127),
46 | random.randint(32, 127))
47 | , font=self.font)
48 | # 划线
49 | # self.draw_lines()
50 | # 重新设置图片大小
51 | self.im = self.im.resize((100, 24))
52 | # 图片转为base64字符串
53 | buffered = io.BytesIO()
54 | self.im.save(buffered, format="JPEG")
55 | img_str = "data:image/png;base64," + str(str(base64.b64encode(buffered.getvalue())).strip('b').strip('\''))
56 | return img_str, code
--------------------------------------------------------------------------------
/app/common/mail.py:
--------------------------------------------------------------------------------
1 |
2 | """mail
3 |
4 | mail module
5 |
6 | PROJECT: BaoAI Backend
7 | AUTHOR: henry <703264459@qq.com>
8 | WEBSITE: http://www.baoai.co
9 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
10 | LICENSE: Apache-2.0
11 | """
12 |
13 | import smtplib
14 | from email.mime.text import MIMEText
15 | from email.header import Header
16 |
17 |
18 |
19 | def mail(sender, password, receiver, from_, to_, subject, message):
20 | '''Send Mail # 发送邮件
21 |
22 | Usage: # 使用:
23 | mail('admin@baoai.co', 'xxxxxxxx', '703264459@qq.com', 'BaoAI', 'henry', 'email test title', 'email content...')
24 |
25 | Args:
26 | sender (str): Sender's mailbox , for example: 'admin@baoai.co' # 发件人邮箱
27 | password (str): 'xxxxxxxx' # Sender's mailbox password # 发件人邮箱密码
28 | receiver (str): '703264459@qq.com' # Recipient mailbox # 收件人邮箱
29 | from_ (str) (str): Sender's nickname # 发件人昵称
30 | to_ (str) (str): Sender's nickname # 收件人昵称
31 | subject (str) (str): email's subject # 邮件标题
32 | message (str) (str): email's content # 邮件内容
33 |
34 | Returns:
35 | dict: result, For example: {'status':True, 'message':'Success'}
36 | '''
37 | try:
38 | msg = MIMEText(message,'plain','utf-8')
39 | msg['From'] = Header(from_,'utf-8')
40 | msg['To'] = Header(to_,'utf-8')
41 | msg['Subject'] = Header(subject,'utf-8')
42 |
43 | server = smtplib.SMTP_SSL("smtp.exmail.qq.com", 465) # SMTP server in sender's mailbox, general port is 25 # 发件人邮箱中的SMTP服务器,一般端口是25
44 | server.login(sender, password) # the sender's mailbox account and password. # 括号中对应的是发件人邮箱账号、邮箱密码
45 | server.sendmail(sender, receiver, msg.as_string()) # the sender's mailbox account, the recipient's mailbox account, and the sending of mail. # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
46 | server.quit() # Close the connection # 关闭连接
47 | return {'status':True, 'message':'Success'}
48 | except Exception as e:
49 | return {'status':False, 'message':"Failed: " + str(e)}
50 |
51 |
52 |
--------------------------------------------------------------------------------
/app/common/mixin.py:
--------------------------------------------------------------------------------
1 | """mixin
2 |
3 | Model predefinition
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import Config, db
13 | from sqlalchemy.ext.declarative import declared_attr
14 | from datetime import datetime
15 |
16 | class TableMixin:
17 | '''Data table object, global settings set public properties and methods # 数据表对象, 全局设置设置公共属性与方法
18 | '''
19 | id = db.Column(db.Integer, primary_key=True)
20 | pid = db.Column(db.Integer, nullable=False, default=0) # parent id # 父ID
21 | title = db.Column(db.String(255), nullable=True)
22 | created = db.Column(
23 | db.DateTime, nullable=False, default=datetime.now) # 记录增加时间
24 | #db.DateTime, nullable=False, default=datetime.utcnow)
25 | updated = db.Column(
26 | db.DateTime, onupdate=datetime.now) # 记录修改时间
27 | #db.DateTime, onupdate=datetime.utcnow)
28 | status = db.Column(db.Boolean, nullable=False, default=True, index=True) # Record status True/1=normal False/0=pause # 记录状态, 1 正常 0 暂停
29 | weight = db.Column(db.Integer, nullable=False, default=0, index=True) # Weight, the higher the value, the higher the order # 权重,值越大排序越前
30 | lang = db.Column(db.String(10), nullable=False, index=True, default='all') # lang: all zh-cn zh-tw en jp kr
31 | uid = db.Column(db.Integer, nullable=False, default=0, index=True) # admin or user id # 用户ID
32 |
33 | @declared_attr
34 | def __tablename__(cls):
35 | _table_prefix = Config.TABLE_PREFIX
36 | return _table_prefix + cls.__name__.lower()
37 |
38 | def __repr__(self):
39 | return (
40 | "<{class_name}("
41 | "id={self.id}, "
42 | "title=\"{self.title}\""
43 | ")>".format(
44 | class_name=self.__class__.__name__,
45 | self=self
46 | )
47 | )
48 |
49 | class PureTableMixin:
50 | id = db.Column(db.Integer, primary_key=True)
51 |
52 | @declared_attr
53 | def __tablename__(cls):
54 | _table_prefix = Config.TABLE_PREFIX
55 | return _table_prefix + cls.__name__.lower()
56 |
57 | class StockTableMixin:
58 | id = db.Column(db.Integer, primary_key=True)
59 | title = db.Column(db.String(20), nullable=True)
60 |
61 | class StockPureTableMixin:
62 | id = db.Column(db.Integer, primary_key=True)
63 |
64 |
65 |
--------------------------------------------------------------------------------
/app/common/param.py:
--------------------------------------------------------------------------------
1 | """param
2 |
3 | Request Parameter
4 | 请求参数
5 |
6 | PROJECT: BaoAI Backend
7 | AUTHOR: henry <703264459@qq.com>
8 | WEBSITE: http://www.baoai.co
9 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
10 | LICENSE: Apache-2.0
11 | """
12 |
13 | from flask_marshmallow import base_fields
14 | from flask_restplus_patched import Parameters, PostFormParameters, JSONParameters
15 |
16 | class BasicPagerParameters(Parameters):
17 | page = base_fields.Integer(required=True)
18 | limit = base_fields.Integer(required=True)
19 |
20 | class PagerParameters(Parameters):
21 | search = base_fields.String(required=False, default='')
22 | sort = base_fields.String(required=False, default='')
23 | order = base_fields.String(required=True, default='asc')
24 | offset = base_fields.Integer(required=True, default=0)
25 | limit = base_fields.Integer(required=True, default=10)
26 | lang = base_fields.String(required=False, default='')
27 |
28 | class PagerJSONParameters(JSONParameters):
29 | search = base_fields.String(required=False, default='')
30 | sort = base_fields.String(required=False, default='')
31 | order = base_fields.String(required=True, default='asc')
32 | offset = base_fields.Integer(required=True, default=0)
33 | limit = base_fields.Integer(required=True, default=10)
34 | lang = base_fields.String(required=False, default='')
35 |
36 | class IDSParameters(JSONParameters):
37 | ids = base_fields.List(base_fields.Integer())
38 |
39 | class IDJSONParameters(JSONParameters):
40 | id = base_fields.Integer(required=True)
41 |
42 | class UIDParameters(Parameters):
43 | """
44 | Uniform ID
45 | """
46 | uid = base_fields.Integer(required=True)
47 |
48 | class IDParameters(Parameters):
49 | """
50 | ID
51 | """
52 | id = base_fields.Integer(required=True)
53 |
54 | class UIDAndIDSParameters(JSONParameters):
55 | """
56 | UID And IDS
57 | """
58 | uid = base_fields.Integer(required=True)
59 | ids = base_fields.List(base_fields.Integer())
60 |
61 | class LangParameters(Parameters):
62 | lang = base_fields.String(required=False)
--------------------------------------------------------------------------------
/app/common/result.py:
--------------------------------------------------------------------------------
1 | """result
2 |
3 | PROJECT: BaoAI Backend
4 | AUTHOR: henry <703264459@qq.com>
5 | WEBSITE: http://www.baoai.co
6 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
7 | LICENSE: Apache-2.0
8 | """
9 |
10 | from flask import current_app,request
11 | from .status import Status
12 | class Result(object):
13 | @staticmethod
14 | def success(data={}, status=Status.SUCCESS.status, message=Status.SUCCESS.message):
15 | ret_json = {
16 | "status": status,
17 | "message": message,
18 | "data": data
19 | }
20 | return ret_json
21 |
22 | @staticmethod
23 | def error(data={}, status=Status.ERROR.status, message=Status.ERROR.message):
24 | ret_json = {
25 | "status": status,
26 | "message": message,
27 | "data": data
28 | }
29 | return ret_json
30 |
--------------------------------------------------------------------------------
/app/common/schema.py:
--------------------------------------------------------------------------------
1 | """schema
2 |
3 | Response Schema
4 | 响应模式
5 |
6 | PROJECT: BaoAI Backend
7 | AUTHOR: henry <703264459@qq.com>
8 | WEBSITE: http://www.baoai.co
9 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
10 | LICENSE: Apache-2.0
11 | """
12 |
13 | from .status import Status
14 | from flask_restplus_patched import ModelSchema
15 | from flask_marshmallow import base_fields
16 |
17 | class BasicSchema(ModelSchema):
18 | status = base_fields.Integer(default=Status.SUCCESS.status)
19 | message = base_fields.String(default=Status.SUCCESS.message)
20 | data = base_fields.Raw()
21 | class Meta:
22 | pass
23 |
24 | class BasicPagerSchema(ModelSchema):
25 | has_prev = base_fields.Boolean()
26 | has_next = base_fields.Boolean()
27 | pages = base_fields.Integer()
28 | page = base_fields.Integer()
29 | lst_size = base_fields.Integer()
30 | total = base_fields.Integer()
31 | items = base_fields.Raw()
32 | class Meta:
33 | pass
34 |
35 | class DeleteSchema(ModelSchema):
36 | delete = base_fields.Integer()
37 | class Meta:
38 | pass
39 |
40 | class ResSchema(ModelSchema):
41 | res = base_fields.Integer()
42 | class Meta:
43 | pass
--------------------------------------------------------------------------------
/app/common/status.py:
--------------------------------------------------------------------------------
1 | """status
2 |
3 | Custom Response Status
4 | 定制响应状态
5 |
6 | PROJECT: BaoAI Backend
7 | AUTHOR: henry <703264459@qq.com>
8 | WEBSITE: http://www.baoai.co
9 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
10 | LICENSE: Apache-2.0
11 | """
12 |
13 | class Status():
14 | class SUCCESS:
15 | status = 200000
16 | message = "Success"
17 |
18 | class ERROR:
19 | status = 200400
20 | message = "Error"
21 |
22 | class TOKEN_SUCCESS:
23 | status = 200001
24 | message = "Token Success"
25 |
26 | class PARAMETER_ERROR:
27 | status = 400422
28 | message = "Parameter Error"
29 |
30 | class FORBIDDEN:
31 | status = 400403
32 | message = "Forbidden!"
33 |
34 | class FILE_NOT_FOUND:
35 | status = 400404
36 | message = "Forbidden!"
37 |
38 | class INTERNAL_ERROR:
39 | status = 500000
40 | message = "Internal Error"
41 |
42 | class TOKEN_ERROR:
43 | status = 500001
44 | message = "Token Error"
45 |
46 | class TOKEN_SIGNATURE_EXPIRED:
47 | status = 500002
48 | message = "Token Signature Expired"
49 |
50 | class TOKEN_BADSIGNATURE:
51 | status = 500003
52 | message = "Token BadSignature"
53 |
54 | class TOKEN_TAMPERED:
55 | status = 500004
56 | message = "Token Tampered"
57 |
58 | class TOKEN_UNKNOWN_REASON:
59 | status = 500005
60 | message = "Error Token With Unknown Reason"
61 |
62 | class TOKEN_ILLEGAL:
63 | status = 500005
64 | message = "Illegal Payload Inside"
65 |
--------------------------------------------------------------------------------
/app/modules/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 | from flask import current_app
3 | import traceback
4 |
5 | def file_name(file_dir):
6 | '''All subdirectories under the directory #目录下所有的子目录
7 |
8 | Args:
9 | file_dir (str) : 目录绝对路径
10 |
11 | Returns:
12 | str : modules dirs # 模块目录
13 |
14 | '''
15 | modules_dirs = []
16 | for root, dirs, files in os.walk(file_dir):
17 | dirs.remove('__pycache__')
18 | modules_dirs = dirs
19 | break
20 | # print('root_dir:', root) # 当前目录路径
21 | # print('sub_dirs:', dirs) # 当前路径下所有子目录
22 | # print('files:', files) # 当前路径下所有非目录子文件
23 | return modules_dirs
24 |
25 |
26 | def init_app(app, **kwargs):
27 | '''init app # 初始化应用
28 |
29 | 1. import_module动态导入所有模块
30 | 2. 执行导入模块的init_app方法
31 |
32 | Args:
33 | app (obj) : flask app
34 |
35 | Returns:
36 | void : void
37 |
38 | '''
39 | basedir = os.path.abspath(os.path.dirname(__file__))
40 | modules_dirs = file_name(basedir)
41 | from importlib import import_module
42 | # for module_name in app.config['ENABLED_MODULES']:
43 | for module_name in modules_dirs:
44 | # import_module('.%s' % module_name, package=__name__).init_app(app, **kwargs)
45 | try:
46 | import_module('.%s' % module_name, package=__name__).init_app(app, **kwargs)
47 | except Exception as e:
48 | print('%s module exception, traceback:\n%s' % (module_name, traceback.format_exc()))
49 |
50 |
--------------------------------------------------------------------------------
/app/modules/admin/__init__.py:
--------------------------------------------------------------------------------
1 | from app.api import api
2 | def init_app(app, **kwargs):
3 | """
4 | Init admin module.
5 | """
6 | from . import resource
7 | api.add_namespace(resource.ns)
--------------------------------------------------------------------------------
/app/modules/admin/model.py:
--------------------------------------------------------------------------------
1 | """dao
2 |
3 | Data Access Object
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 | import time
12 | from app import db
13 | from flask import current_app
14 | from werkzeug.security import generate_password_hash, check_password_hash
15 | # serializer for JWT
16 | from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
17 | # exceptions for JWT
18 | from itsdangerous import SignatureExpired, BadSignature, BadData
19 | from app.common.mixin import *
20 | from app.common.result import Result
21 | from app.common.status import Status
22 |
23 | class Admin(TableMixin, db.Model):
24 | __tablename__ = 'admin'
25 | username = db.Column(db.String(32), unique=True, index=True, nullable=False)
26 | email = db.Column(db.String(255), unique=True, nullable=True)
27 | password_hash = db.Column(db.String(128))
28 | nickname = db.Column(db.String(32))
29 | last_login_time = db.Column(db.DateTime) # last login time
30 | last_login_ip = db.Column(db.String(32), nullable=True) # last login ip
31 | current_login_ip = db.Column(db.String(32), nullable=True) # current login IP
32 | current_login_time = db.Column(db.DateTime) # current login time
33 | login_failure = db.Column(db.Integer, nullable=False, default=0) # login failure count
34 | avatar = db.Column(db.String(255), nullable=True) # avatar url
35 | locked = db.Column(db.Boolean(), nullable=False, default=False)
36 |
37 | def __repr__(self):
38 | return '' % self.username
39 |
40 | @property
41 | def password(self):
42 | raise AttributeError("password is not a readable attribute!")
43 |
44 | @password.setter
45 | def password(self, password):
46 | self.password_hash = generate_password_hash(password)
47 |
48 | def verify_password(self, password):
49 | """Verify Password # 验证密码
50 | """
51 | return check_password_hash(self.password_hash, password)
52 |
53 | def generate_token(self, expires=3600):
54 | """Generate Token # 产生令牌
55 |
56 | token contains id, username and timestamp
57 | 令牌包含:id, username, 时间截
58 |
59 | """
60 | s = Serializer(
61 | secret_key=current_app.config['SECRET_KEY'],
62 | salt=current_app.config['AUTH_SALT'],
63 | expires_in=expires
64 | )
65 | timestamp = time.time()
66 | # token contains id, username and timestamp
67 | token = s.dumps({
68 | 'id': self.id,
69 | 'username': self.username,
70 | 'iat': timestamp
71 | }).decode()
72 | return token
73 |
74 | def generate_new_token(self, expires, username, rftoken):
75 | """Generate new token with reflesh token # 使用刷新令牌获取新令牌
76 |
77 | Args:
78 | expires (int): expires time (unit: second)
79 | username (str): username
80 | rftoken (str): reflesh token
81 |
82 | Returns:
83 | str: new token, default is None
84 |
85 | """
86 | token = None
87 | res = Admin.confirm(rftoken)
88 | if res['status'] != Status.TOKEN_SUCCESS.status :
89 | return token
90 | if res['data']['username'] != username :
91 | return token
92 | s = Serializer(
93 | secret_key=current_app.config['SECRET_KEY'],
94 | salt=current_app.config['AUTH_SALT'],
95 | expires_in=expires
96 | )
97 | timestamp = time.time()
98 | # token contains id, username and timestamp
99 | token = s.dumps({
100 | 'id': self.id,
101 | 'username': self.username,
102 | 'iat': timestamp
103 | }).decode()
104 | return token
105 |
106 | @staticmethod
107 | def confirm(token):
108 | """Confirm token # 确认令牌,返回确认状态
109 |
110 | Args:
111 | token (str): To be verified token
112 |
113 | Returns:
114 | object: app.common.result.Result
115 |
116 | """
117 | # token decoding
118 | s = Serializer(
119 | secret_key=current_app.config['SECRET_KEY'],
120 | salt=current_app.config['AUTH_SALT'])
121 | data = {}
122 | try:
123 | data = s.loads(token)
124 | # token decoding faild
125 | # if it happend a plenty of times, there might be someone
126 | # trying to attact your server, so it should be a warning.
127 | except SignatureExpired:
128 | msg = 'token expired'
129 | # current_app.logger.warning(msg)
130 | return Result.error(data,status=Status.TOKEN_SIGNATURE_EXPIRED.status, message=Status.TOKEN_SIGNATURE_EXPIRED.message)
131 | except BadSignature as e:
132 | encoded_payload = e.payload
133 | if encoded_payload is not None:
134 | try:
135 | s.load_payload(encoded_payload)
136 | except BadData:
137 | # the token is tampered.
138 | msg = 'token tampered'
139 | return Result.error(data,status=Status.TOKEN_TAMPERED.status, message=Status.TOKEN_TAMPERED.message)
140 | msg = 'badSignature of token'
141 | return Result.error(data,status=Status.TOKEN_BADSIGNATURE.status, message=Status.TOKEN_BADSIGNATURE.message)
142 | except:
143 | msg = 'wrong token with unknown reason'
144 | return Result.error(data,status=Status.TOKEN_UNKNOWN_REASON.status, message=Status.TOKEN_UNKNOWN_REASON.message)
145 | if ('id' not in data) :
146 | msg = 'illegal payload inside'
147 | return Result.error(data,status=Status.TOKEN_ILLEGAL.status, message=Status.TOKEN_ILLEGAL.message)
148 | return Result.success(data=data,status=Status.TOKEN_SUCCESS.status, message=Status.TOKEN_SUCCESS.message)
149 |
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/app/modules/admin/param.py:
--------------------------------------------------------------------------------
1 | """param
2 |
3 | Request Parameter
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 | from flask_marshmallow import base_fields
12 | from marshmallow import validate, ValidationError
13 | from flask_restplus_patched import Parameters, PostFormParameters, JSONParameters
14 | from .schema import *
15 |
16 | def validate_length(value):
17 | if len(value) < 3 or len(value) > 30:
18 | raise ValidationError('Length [3-30]')
19 |
20 | class AdminLoginParameters(JSONParameters):
21 | username = base_fields.String(required=True, validate=validate_length)
22 | password = base_fields.String(required=True)
23 |
24 | class AdminParameters(JSONParameters, AdminSchema):
25 | class Meta(AdminSchema.Meta):
26 | pass
27 |
28 | class FindPassParameters(JSONParameters):
29 | email = base_fields.String(required=True, validate=validate.Email(error='Format Error'))
30 |
31 | class RefleshTokenParameters(JSONParameters):
32 | rftoken = base_fields.String(required=True)
33 | username = base_fields.String(required=True)
34 |
35 | class UidsRidsParameters(JSONParameters):
36 | rids = base_fields.List(base_fields.Integer())
37 | uids = base_fields.List(base_fields.Integer())
38 |
39 |
--------------------------------------------------------------------------------
/app/modules/admin/schema.py:
--------------------------------------------------------------------------------
1 | """schema
2 |
3 | Response Schema
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 | from flask_restplus_patched import ModelSchema
12 | from flask_marshmallow import base_fields
13 | from app.common.schema import BasicSchema,BasicPagerSchema
14 | from .model import *
15 |
16 | class AdminSchema(ModelSchema):
17 | """
18 | Base Admin schema exposes only the most general fields.
19 | """
20 | class Meta:
21 | model = Admin
22 |
23 | class AdminListPagerSchema(ModelSchema):
24 | total = base_fields.Integer()
25 | rows = base_fields.Nested(AdminSchema(exclude=['password_hash']), many=True)
26 | class Meta:
27 | pass
28 |
29 | class RolesSchema(ModelSchema):
30 | rid = base_fields.Integer()
31 | title = base_fields.String()
32 | resources = base_fields.String()
33 | class Meta:
34 | pass
35 |
36 | class RolesDetailSchema(ModelSchema):
37 | uid = base_fields.Integer()
38 | rids = base_fields.List(base_fields.Integer())
39 | rids_str = base_fields.String()
40 | resources_ids = base_fields.List(base_fields.Integer())
41 | resources_ids_str = base_fields.String()
42 | titles = base_fields.String()
43 | roles = base_fields.Nested(RolesSchema, many=True)
44 | class Meta:
45 | pass
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/app/modules/adminroles/__init__.py:
--------------------------------------------------------------------------------
1 | """adminroles
2 |
3 | Init adminroles module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app.api import api
13 | def init_app(app, **kwargs):
14 | """
15 | Init adminroles module.
16 | """
17 | from . import resource
18 | api.add_namespace(resource.ns)
--------------------------------------------------------------------------------
/app/modules/adminroles/model.py:
--------------------------------------------------------------------------------
1 | """model
2 |
3 | Database Table Model
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import db
13 | from app.common.mixin import *
14 |
15 | class AdminRoles(TableMixin, db.Model):
16 | __tablename__ = 'admin_roles'
17 | uid = db.Column(db.Integer, nullable=False)
18 | rid = db.Column(db.Integer, nullable=False)
19 | __table_args__ = (
20 | db.UniqueConstraint('uid', 'rid', name='uix_admin_roles_uid_rid'),
21 | )
22 |
23 | def __repr__(self):
24 | return '' % (self.id, self.uid, self.rid)
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/modules/adminroles/param.py:
--------------------------------------------------------------------------------
1 | from flask_marshmallow import base_fields
2 | from marshmallow import validate
3 | from flask_restplus_patched import Parameters, PostFormParameters, JSONParameters
4 | from app.common.param import BasicPagerParameters, PagerParameters, PagerJSONParameters
5 | from .schema import *
6 |
7 |
--------------------------------------------------------------------------------
/app/modules/adminroles/resource.py:
--------------------------------------------------------------------------------
1 | from app import db
2 | from flask import current_app,request
3 | from app.common.status import Status
4 | from app.common.schema import *
5 | from app.common.param import *
6 | from flask_restplus_patched import Resource, Namespace, abort, HTTPStatus
7 | from app.common.result import Result
8 | from .model import *
9 | from .schema import *
10 | from .param import *
11 | import random
12 | import string
13 | from sqlalchemy import or_
14 |
15 | ns = Namespace("adminroles", description="adminroles API Resource")
16 |
--------------------------------------------------------------------------------
/app/modules/adminroles/schema.py:
--------------------------------------------------------------------------------
1 | from flask_restplus_patched import ModelSchema
2 | from flask_marshmallow import base_fields
3 | from app.common.schema import BasicSchema,BasicPagerSchema
4 | from .model import *
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/modules/attachments/__init__.py:
--------------------------------------------------------------------------------
1 | """attachments
2 |
3 | Init attachments module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app.api import api
13 | def init_app(app, **kwargs):
14 | """
15 | Init attachments module.
16 | """
17 | from . import resource
18 | api.add_namespace(resource.ns)
--------------------------------------------------------------------------------
/app/modules/attachments/model.py:
--------------------------------------------------------------------------------
1 | """model
2 |
3 | Database Table Model
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import db
13 | from app.common.mixin import *
14 |
15 | class Attachments(TableMixin, db.Model):
16 | __tablename__ = 'attachments'
17 | admin_id = db.Column(db.Integer, nullable=False, default=0)
18 | user_id = db.Column(db.Integer, nullable=False, default=0)
19 | module_name = db.Column(db.String(100), nullable=False, default='attachments') # Module Name
20 | module_obj_id = db.Column(db.Integer, nullable=False, default=0) # Module Object ID
21 | url = db.Column(db.String(255), nullable=False)
22 | uuid = db.Column(db.String(100), nullable=False)
23 | imagewidth = db.Column(db.String(30), nullable=False, default="0")
24 | imageheight = db.Column(db.String(30), nullable=False, default="0")
25 | imagetype = db.Column(db.String(30), nullable=True)
26 | imageframes = db.Column(db.Integer, nullable=False, default=0)
27 | filesize = db.Column(db.Integer, nullable=False, default=0)
28 | mimetype = db.Column(db.String(100), nullable=True)
29 | isimage = db.Column(db.Boolean(), nullable=False, default=True) # is image, 1/True: Image 0/False: File
30 | iscover = db.Column(db.Boolean(), nullable=False, default=False) # is cover, 1/True: cover 0/False: not cover
31 | weight = db.Column(db.Integer, nullable=False, default=0)
32 | extparam = db.Column(db.String(255), nullable=True)
33 | storage = db.Column(db.String(100), nullable=False, default="local")
34 | sha1 = db.Column(db.String(40), nullable=True)
35 | md5 = db.Column(db.String(40), nullable=True)
36 | category_id = db.Column(db.Integer, nullable=False, default=0)
37 | category_main = db.Column(db.String(100), nullable=False, index=True, default='uncategorized')
38 | category_sub = db.Column(db.String(100), nullable=False, index=True, default='uncategorized')
39 |
40 | def __repr__(self):
41 | return '' % self.title
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/app/modules/attachments/param.py:
--------------------------------------------------------------------------------
1 | """param
2 |
3 | Request Parameter
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from flask_marshmallow import base_fields
13 | from marshmallow import validate
14 | from flask_restplus_patched import JSONParameters, Parameters, PostFormParameters
15 | from .schema import *
16 | from app.common.param import PagerParameters
17 |
18 | class AttachmentsParameters(JSONParameters, AttachmentsSchema):
19 | class Meta(AttachmentsSchema.Meta):
20 | pass
21 |
22 | class ExtendPagerParameters(PagerParameters):
23 | module_name = base_fields.String(required=False)
24 | module_obj_id = base_fields.Integer(required=False)
25 | category_id = base_fields.Integer(required=False)
26 |
27 | class CEditorFileBrowserUploadParameters(PostFormParameters):
28 | CKEditorFuncNum = base_fields.Integer(required=False)
29 | CKEditor = base_fields.String(required=False)
30 | langCode = base_fields.String(required=False)
31 | ckCsrfToken = base_fields.String(required=False)
32 |
33 | class RemoteImgURLParameters(Parameters):
34 | remote_img_url = base_fields.String(required=False)
--------------------------------------------------------------------------------
/app/modules/attachments/schema.py:
--------------------------------------------------------------------------------
1 | """schema
2 |
3 | Response Schema
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from flask_restplus_patched import ModelSchema
13 | from flask_marshmallow import base_fields
14 | from app.common.schema import BasicSchema,BasicPagerSchema
15 | from .model import *
16 |
17 | class AttachmentsSchema(ModelSchema):
18 | class Meta:
19 | model = Attachments
20 |
21 | class AttachmentsListPagerSchema(ModelSchema):
22 | total = base_fields.Integer()
23 | rows = base_fields.Nested(AttachmentsSchema, many=True)
24 | class Meta:
25 | pass
26 |
27 | class CKeditorUploadErrorSchema(ModelSchema):
28 | message = base_fields.String()
29 | class Meta:
30 | pass
31 |
32 | class AttachmentsCKeditorUploadSchema(ModelSchema):
33 | uploaded = base_fields.Integer()
34 | fileName = base_fields.String()
35 | url = base_fields.String()
36 | error = base_fields.Nested(CKeditorUploadErrorSchema)
37 | class Meta:
38 | pass
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/modules/category/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Category module
3 |
4 | PROJECT: BaoAI Backend
5 | AUTHOR: henry <703264459@qq.com>
6 | WEBSITE: http://www.baoai.co
7 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
8 | LICENSE: Apache-2.0
9 | CREATEDATE: 2019-08-04 10:04:19
10 | """
11 |
12 | from app.api import api
13 |
14 | def init_app(app, **kwargs):
15 | """
16 | Init Category module.
17 | """
18 | from . import resource
19 | api.add_namespace(resource.ns)
--------------------------------------------------------------------------------
/app/modules/category/model.py:
--------------------------------------------------------------------------------
1 | """
2 | Category database models
3 |
4 | PROJECT: BaoAI Backend
5 | AUTHOR: henry <703264459@qq.com>
6 | WEBSITE: http://www.baoai.co
7 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
8 | LICENSE: Apache-2.0
9 | CREATEDATE: 2019-08-04 10:04:19
10 | """
11 |
12 | from app import db
13 | from sqlalchemy.schema import FetchedValue
14 | from app.common.mixin import *
15 |
16 | class Category(TableMixin, db.Model):
17 | """
18 | Category database model.
19 | """
20 | __tablename__ = 'category'
21 | ismenu = db.Column(db.Boolean(), nullable=True, unique=False, index=False, default='True')
22 | pid = db.Column(db.Integer(), nullable=False, unique=False, index=True, default='0')
23 | title = db.Column(db.String(255), nullable=False, unique=False, index=True)
24 | alias = db.Column(db.String(100), nullable=True, unique=False, index=False)
25 | weight = db.Column(db.Integer(), nullable=False, unique=False, index=True, default='0')
26 | keywords = db.Column(db.String(255), nullable=True, unique=False, index=False)
27 | summary = db.Column(db.Text(), nullable=True, unique=False, index=False)
28 | content = db.Column(db.Text(), nullable=True, unique=False, index=False)
29 | link_type = db.Column(db.String(30), nullable=True, unique=False, index=False)
30 | inner_link = db.Column(db.Integer(), nullable=True, unique=False, index=False, default='0')
31 | link_target = db.Column(db.String(255), nullable=True, unique=False, index=False, default='_blank')
32 | link = db.Column(db.String(255), nullable=True, unique=False, index=False)
33 | block_link = db.Column(db.Integer(), nullable=True, unique=False, index=False)
34 | article_link = db.Column(db.Integer(), nullable=True, unique=False, index=False)
35 | articles = db.Column(db.Integer(), nullable=True, unique=False, index=False)
36 | route_link = db.Column(db.String(255), nullable=True, unique=False, index=False)
37 | cover = db.Column(db.String(255), nullable=True, unique=False, index=False)
38 | views = db.Column(db.Integer(), nullable=True, unique=False, index=False, default='0')
39 | # tree
40 | treepath = db.Column(db.String(255), nullable=True) # tree path, for example: .2.120. , 0 does not need to be at the front # 树路径
41 | treegrade = db.Column(db.Integer, nullable=True) # Tree depth, top level is 0, .2.120. is 2 # 树深度
42 | # tree path weight, Weight for tree sort. for example: 2000.2.1500.120. , The weight of node(id = 2) is 2000, The weight of node(id = 120) is 1500
43 | # 树路径权重,用于树形排序。如:2000.2.1500.120. , 结点ID是2 的权重是2000 , 结点ID是120的权重是1500
44 | treepathweight = db.Column(db.String(255), nullable=True)
45 |
46 | def __repr__(self):
47 | return (
48 | "<{class_name}("
49 | "id={self.id}, "
50 | "title=\"{self.title}\""
51 | ")>".format(
52 | class_name=self.__class__.__name__,
53 | self=self
54 | )
55 | )
56 |
--------------------------------------------------------------------------------
/app/modules/category/param.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Category Module Request Parameter
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | CREATEDATE: 2019-08-04 10:04:19
11 | """
12 |
13 | from flask_marshmallow import base_fields
14 | from marshmallow import validate
15 | from flask_restplus_patched import Parameters, PostFormParameters, JSONParameters
16 | from .schema import *
17 | from app.common.param import PagerParameters
18 |
19 | class CategoryParameters(JSONParameters, CategorySchema):
20 | """
21 | Category Parameters
22 | """
23 | class Meta(CategorySchema.Meta):
24 | pass
25 |
26 | class ExtendPagerParameters(PagerParameters):
27 | articles = base_fields.Integer(required=False)
28 | books_category_id = base_fields.Integer(required=False)
29 | nav_category_id = base_fields.Integer(required=False)
30 | is_book = base_fields.Boolean(required=False)
31 | is_main = base_fields.Boolean(required=False)
32 |
33 | class NewsExtendPagerParameters(PagerParameters):
34 | articles = base_fields.Integer(required=False)
35 | news_category_id = base_fields.Integer(required=False)
36 |
37 | class FieldParameters(Parameters):
38 | category = base_fields.Integer(required=False)
39 | field = base_fields.String(required=False)
40 |
41 |
--------------------------------------------------------------------------------
/app/modules/category/schema.py:
--------------------------------------------------------------------------------
1 | """schema
2 |
3 | Category Module Response Schema
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | CREATEDATE: 2019-08-04 10:04:19
11 | """
12 |
13 | from flask_restplus_patched import ModelSchema
14 | from flask_marshmallow import base_fields
15 | from .model import *
16 |
17 | class CategorySchema(ModelSchema):
18 | """
19 | Category schema
20 | """
21 | class Meta:
22 | model = Category
23 |
24 | class CategoryListPagerSchema(CategorySchema):
25 | """
26 | Category pager schema
27 | """
28 | total = base_fields.Integer()
29 | rows = base_fields.Nested(CategorySchema, many=True)
30 | class Meta:
31 | pass
32 |
33 | class CategoryFieldSchema(ModelSchema):
34 | """
35 | Category Field schema
36 | """
37 | title = base_fields.String()
38 | field = base_fields.String()
39 | class Meta:
40 | pass
--------------------------------------------------------------------------------
/app/modules/configs/__init__.py:
--------------------------------------------------------------------------------
1 | """configs
2 |
3 | Init configs module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app.api import api
13 | def init_app(app, **kwargs):
14 | """
15 | Init configs module.
16 | """
17 | from . import resource
18 | api.add_namespace(resource.ns)
--------------------------------------------------------------------------------
/app/modules/configs/model.py:
--------------------------------------------------------------------------------
1 | """model
2 |
3 | Database Table Model
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import db
13 | from app.common.mixin import *
14 |
15 | class Configs(TableMixin, db.Model):
16 | """Model Class"""
17 | __tablename__ = 'configs'
18 | uid = db.Column(db.Integer, nullable=False)
19 | module = db.Column(db.String(100), nullable=False)
20 | section = db.Column(db.String(100), nullable=False)
21 | keys = db.Column(db.String(100), nullable=False)
22 | value = db.Column(db.Text(), nullable=True)
23 | __table_args__ = (
24 | db.UniqueConstraint('module', 'section', 'keys', 'lang', name='uix_configs_module_section_keys_lang'),
25 | )
26 |
27 | def __repr__(self):
28 | """Class Serialization"""
29 | return '' % (self.module + '.' + self.section + '.' + self.key + '.' + self.lang + ' = ' + self.value)
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/modules/configs/param.py:
--------------------------------------------------------------------------------
1 | """param
2 |
3 | Request Parameter
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from flask_marshmallow import base_fields
13 | from marshmallow import validate
14 | from flask_restplus_patched import Parameters, PostFormParameters, JSONParameters
15 | from .schema import *
16 | from app.common.param import PagerParameters
17 |
18 | class ConfigsParameters(JSONParameters, ConfigsSchema):
19 | """
20 | Configs Parameters
21 | """
22 | class Meta(ConfigsSchema.Meta):
23 | pass
24 |
25 | class ExtendPagerParameters(PagerParameters):
26 | module_name = base_fields.String(required=False)
27 | section = base_fields.String(required=False)
28 |
29 |
--------------------------------------------------------------------------------
/app/modules/configs/resource.py:
--------------------------------------------------------------------------------
1 | """resource
2 |
3 | API Resource Of Configs Module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import db
13 | from flask import current_app,request
14 | from app.common.schema import *
15 | from app.common.param import *
16 | from app.common.wrap import *
17 | from flask_restplus_patched import Resource, Namespace, abort, HTTPStatus
18 | from sqlalchemy import or_
19 | from .model import *
20 | from .schema import *
21 | from .param import *
22 | from .dao import *
23 |
24 | ns = Namespace("configs", description="configs API Resource")
25 |
26 | @ns.route("/")
27 | class ConfigsAPI(Resource):
28 | """
29 | configs module resource main service: add/delete/edit/view
30 | """
31 | @ns.parameters(ConfigsParameters(dump_only=['id']))
32 | @ns.response(ConfigsSchema(many=False))
33 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
34 | def post(self, args):
35 | """
36 | add
37 | """
38 | configs = None
39 | configsDao = ConfigsDao()
40 | try:
41 | configs = configsDao.add(args)
42 | except Exception as e:
43 | abort(500, e)
44 | return configs
45 |
46 | @ns.parameters(ConfigsParameters())
47 | @ns.response(ConfigsSchema())
48 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
49 | def put(self, args):
50 | """
51 | edit
52 | """
53 | record = None
54 | configsDao = ConfigsDao()
55 | try:
56 | record = configsDao.edit(args)
57 | except Exception as e:
58 | abort(500, e)
59 | return record
60 |
61 | @auth()
62 | @ns.parameters(IDSParameters())
63 | @ns.response(BasicSchema(many=False))
64 | def delete(self, args):
65 | """
66 | delete
67 | """
68 | result = False
69 | ids = args.get('ids')
70 | configsDao = ConfigsDao()
71 | try:
72 | result = configsDao.delete(ids)
73 | except Exception as e:
74 | abort(500, e)
75 | return {"status":result}
76 |
77 | @auth()
78 | @ns.response(ConfigsSchema())
79 | @ns.response(code=HTTPStatus.NO_CONTENT)
80 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
81 | def get(self, args):
82 | """
83 | view
84 | """
85 | record = None
86 | configsDao = ConfigsDao()
87 | id = request.uid
88 | record = configsDao.getById(id)
89 | return record
90 |
91 | @ns.route("/list")
92 | class ConfigsListAPI(Resource):
93 | """
94 | configs module resource list service
95 | """
96 | @auth()
97 | @ns.parameters(ExtendPagerParameters())
98 | @ns.response(ConfigsListPagerSchema(many=False))
99 | @ns.response(code=500)
100 | def get(self,args):
101 | """
102 | view list
103 | """
104 | data = {}
105 | args.setdefault('search','')
106 | args.setdefault('sort','')
107 | args.setdefault('module_name','')
108 | args.setdefault('section','')
109 | search = args.pop('search')
110 | sort = args.pop('sort')
111 | order = args.pop('order')
112 | offset = args.pop('offset')
113 | limit = args.pop('limit')
114 | lang = args.pop('lang')
115 | module_name = args.pop('module_name')
116 | section = args.pop('section')
117 | configsDao = ConfigsDao()
118 | data = configsDao.getList(search, sort, order, offset, limit, lang, module_name, section)
119 | return data
120 |
121 | @ns.route("/modules")
122 | class ConfigsModulesListAPI(Resource):
123 | """
124 | all modules list service # 查询所有模块列表
125 | """
126 | #@auth()
127 | @ns.response(ConfigsSchema(only=['module'], many=True))
128 | @ns.response(code=500)
129 | def post(self):
130 | """
131 | view list
132 | """
133 | configsDao = ConfigsDao()
134 | records = configsDao.getModules()
135 | return records
136 |
137 | @ns.route("/sections")
138 | class ConfigsSectionsListAPI(Resource):
139 | """
140 | sections list service by module # 获取某个模块下的所有类别(section)
141 | """
142 | #@auth()
143 | @ns.parameters(ConfigsParameters(only=['module']))
144 | @ns.response(ConfigsSchema(only=['section'], many=True))
145 | @ns.response(code=500)
146 | def post(self,args):
147 | """
148 | view list
149 | """
150 | module = args.get('module')
151 | configsDao = ConfigsDao()
152 | records = configsDao.getSections(module)
153 | return records
154 |
155 | @ns.route("/keys")
156 | class ConfigsKeysListAPI(Resource):
157 | """
158 | keys list service by module, secton and lang # 由模块、类别和语言获取键值对
159 | """
160 | #@auth()
161 | @ns.parameters(ConfigsParameters(only=['module', 'section', 'lang']))
162 | @ns.response(ConfigsSchema(only=['keys', 'value', 'title'], many=True))
163 | @ns.response(code=500)
164 | def post(self,args):
165 | """
166 | view list
167 | """
168 | module = args.get('module')
169 | section = args.get('section')
170 | lang = args.get('lang')
171 | configsDao = ConfigsDao()
172 | records = configsDao.getKeys(module, section, lang)
173 | return records
174 |
175 | @ns.route("/value")
176 | class ConfigsValueAPI(Resource):
177 | """
178 | get value with module, section , lang and key # 由模块、类别、语言和键获取值
179 | """
180 | #@auth()
181 | @ns.parameters(ConfigsParameters(only=['module', 'section', 'lang', 'keys']))
182 | @ns.response(ConfigsSchema(many=False))
183 | @ns.response(code=500)
184 | def post(self,args):
185 | """
186 | view list
187 | """
188 | module = args.get('module')
189 | section = args.get('section')
190 | lang = args.get('lang')
191 | key = args.get('keys')
192 | configsDao = ConfigsDao()
193 | records = configsDao.getValue(module, section, lang, key)
194 | return records
195 |
196 | @ns.route("/models")
197 | class ConfigsModelsListAPI(Resource):
198 | """
199 | Get Models List
200 | """
201 | @auth()
202 | @ns.response(ConfigsModelsSchema(many=True))
203 | @ns.response(code=500)
204 | def get(self):
205 | """
206 | view list
207 | """
208 | configsDao = ConfigsDao()
209 | result = configsDao.getModels()
210 | return result
211 |
212 |
--------------------------------------------------------------------------------
/app/modules/configs/schema.py:
--------------------------------------------------------------------------------
1 | """schema
2 |
3 | Response Schema
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from flask_restplus_patched import ModelSchema
13 | from flask_marshmallow import base_fields
14 | from .model import *
15 |
16 | class ConfigsSchema(ModelSchema):
17 | """
18 | Configs schema
19 | """
20 | class Meta:
21 | model = Configs
22 |
23 | class ConfigsListPagerSchema(ModelSchema):
24 | """
25 | Configs list pager schema
26 | """
27 | total = base_fields.Integer()
28 | rows = base_fields.Nested(ConfigsSchema, many=True)
29 | class Meta:
30 | pass
31 |
32 | class ConfigsModelsSchema(ModelSchema):
33 | """
34 | Get Models list
35 | """
36 | model = base_fields.String()
37 | module = base_fields.String()
38 | module_name = base_fields.String()
39 | tablename = base_fields.String()
40 | model = base_fields.String()
41 | columns = base_fields.List(base_fields.String(), many=True)
42 | class Meta:
43 | pass
44 |
45 |
--------------------------------------------------------------------------------
/app/modules/iris/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | IRIS module
3 |
4 | PROJECT: BaoAI Backend
5 | AUTHOR: henry <703264459@qq.com>
6 | WEBSITE: http://www.baoai.co
7 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
8 | LICENSE: Apache-2.0
9 | CREATEDATE: 2019-08-23 16:18:40
10 | """
11 |
12 | from app.api import api
13 |
14 | def init_app(app, **kwargs):
15 | """
16 | Init IRIS module.
17 | """
18 | from . import resource
19 | api.add_namespace(resource.ns)
--------------------------------------------------------------------------------
/app/modules/iris/model.py:
--------------------------------------------------------------------------------
1 | """
2 | IRIS database models
3 |
4 | PROJECT: BaoAI Backend
5 | AUTHOR: henry <703264459@qq.com>
6 | WEBSITE: http://www.baoai.co
7 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
8 | LICENSE: Apache-2.0
9 | CREATEDATE: 2019-08-23 16:18:40
10 | """
11 |
12 | from app import db
13 | from sqlalchemy.schema import FetchedValue
14 | from app.common.mixin import *
15 |
16 | class Iris(PureTableMixin, db.Model):
17 | """
18 | IRIS database model.
19 | """
20 | __tablename__ = 'iris'
21 | sepal_length = db.Column(db.Float(), nullable=True, unique=False, index=False)
22 | sepal_width = db.Column(db.Float(), nullable=True, unique=False, index=False)
23 | petal_length = db.Column(db.Float(), nullable=True, unique=False, index=False)
24 | petal_width = db.Column(db.Float(), nullable=True, unique=False, index=False)
25 | irisclass = db.Column(db.String(30), nullable=True, unique=False, index=False)
26 |
27 | def __repr__(self):
28 | return (
29 | "<{class_name}("
30 | "id={self.id}"
31 | ")>".format(
32 | class_name=self.__class__.__name__,
33 | self=self
34 | )
35 | )
36 |
--------------------------------------------------------------------------------
/app/modules/iris/param.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | IRIS Module Request Parameter
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | CREATEDATE: 2019-08-23 16:18:40
11 | """
12 |
13 | from flask_marshmallow import base_fields
14 | from marshmallow import validate
15 | from flask_restplus_patched import Parameters, PostFormParameters, JSONParameters
16 | from .schema import *
17 |
18 |
19 | class IrisParameters(JSONParameters, IrisSchema):
20 | """
21 | IRIS Parameters
22 | """
23 | class Meta(IrisSchema.Meta):
24 | pass
25 |
26 | class IrisLinearPredictParameters(Parameters):
27 | feature_select = base_fields.String(required=False) # Feature selection of iris, including sepals and petals length and width # 鸢尾花特征选择,包括萼片和花瓣长度、宽度
28 | feature_value = base_fields.Float(required=False) # Corresponding value of iris # 鸢尾花对应特征值
29 | linear_select = base_fields.String(required=False) # Linear regression algorithm selection # 线性回归算法选择
30 | feature_select_predict = base_fields.String(required=False) # Prediction feature selection of iris # 鸢尾花预测特征选择
31 |
32 | class IrisClassifyPredictParameters(Parameters):
33 | sepal_length_logic = base_fields.Float(required=False)
34 | sepal_width_logic = base_fields.Float(required=False)
35 | petal_length_logic = base_fields.Float(required=False)
36 | petal_width_logic = base_fields.Float(required=False)
37 | logic_select = base_fields.String(required=False)
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/modules/iris/resource.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | RESTful API IRIS resource
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | CREATEDATE: 2019-08-23 16:18:40
11 | """
12 |
13 | from app import db
14 | from flask import current_app,request
15 | from app.common.schema import *
16 | from app.common.param import *
17 | from app.common.wrap import *
18 | from flask_restplus_patched import Resource, Namespace, abort, HTTPStatus
19 | from sqlalchemy import or_
20 | from .model import *
21 | from .schema import *
22 | from .param import *
23 | from .dao import *
24 |
25 |
26 | ns = Namespace("iris", description="RESTful API IRIS resource")
27 |
28 | @ns.route("/")
29 | class IrisAPI(Resource):
30 | """
31 | IRIS module resource main service: add/delete/edit/view
32 | """
33 | @ns.parameters(IrisParameters(dump_only=['id']))
34 | @ns.response(IrisSchema(many=False))
35 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
36 | def post(self, args):
37 | """
38 | add
39 | """
40 | record = None
41 | irisDao = IrisDao()
42 | try:
43 | record = irisDao.add(args)
44 | except Exception as e:
45 | abort(500, e)
46 | return record
47 |
48 | @ns.parameters(IrisParameters())
49 | @ns.response(IrisSchema())
50 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
51 | def put(self, args):
52 | """
53 | edit
54 | """
55 | record = None
56 | irisDao = IrisDao()
57 | try:
58 | record = irisDao.edit(args)
59 | except Exception as e:
60 | abort(500, e)
61 | return record
62 |
63 | @auth()
64 | @ns.parameters(IDSParameters())
65 | @ns.response(BasicSchema(many=False))
66 | def delete(self, args):
67 | """
68 | delete
69 | """
70 | result = False
71 | ids = args.get('ids')
72 | irisDao = IrisDao()
73 | try:
74 | result = irisDao.delete(ids)
75 | except Exception as e:
76 | abort(500, e)
77 | return {"status":result}
78 |
79 | @auth()
80 | @ns.parameters(IDParameters())
81 | @ns.response(IrisSchema())
82 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
83 | def get(self, args):
84 | """
85 | view
86 | """
87 | record = None
88 | irisDao = IrisDao()
89 | id = args.get('id')
90 | record = irisDao.getById(id)
91 | return record
92 |
93 | @ns.route("/list")
94 | class IrisListAPI(Resource):
95 | """
96 | IRIS module resource list service
97 | """
98 | @auth()
99 | @ns.parameters(PagerParameters())
100 | @ns.response(IrisListPagerSchema(many=False))
101 | @ns.response(code=500)
102 | def get(self,args):
103 | """
104 | view list
105 | """
106 | data = {}
107 | args.setdefault('search','')
108 | args.setdefault('sort','')
109 | args.setdefault('lang','')
110 | search = args.pop('search')
111 | sort = args.pop('sort')
112 | order = args.pop('order')
113 | offset = args.pop('offset')
114 | limit = args.pop('limit')
115 | lang = args.pop('lang')
116 |
117 | irisDao = IrisDao()
118 |
119 | data = irisDao.getListByLang(search, sort, order, offset, limit, lang)
120 |
121 | return data
122 |
123 | @ns.route("/linear_predict")
124 | class IrisLinearPredictAPI(Resource):
125 | @auth()
126 | @ns.parameters(IrisLinearPredictParameters())
127 | @ns.response(IrisPredictSchema(many=False))
128 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
129 | def get(self, args):
130 | """Regression prediction 回归预测
131 |
132 | """
133 | data = {}
134 | args.setdefault('feature_select','')
135 | args.setdefault('feature_value',1)
136 | args.setdefault('linear_select','')
137 | args.setdefault('feature_select_predict','')
138 | feature_select = args.pop('feature_select')
139 | feature_value = args.pop('feature_value')
140 | linear_select = args.pop('linear_select')
141 | feature_select_predict = args.pop('feature_select_predict')
142 | irisDao = IrisDao()
143 | data = irisDao.linearPredict(feature_select, feature_value, linear_select, feature_select_predict)
144 | return data
145 |
146 | @ns.route("/classify_predict")
147 | class IrisClassifyPredictAPI(Resource):
148 | @auth()
149 | @ns.parameters(IrisClassifyPredictParameters())
150 | @ns.response(IrisPredictSchema(many=False))
151 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
152 | def get(self, args):
153 | """
154 | classify predict # 分类预测
155 | """
156 | data = {}
157 | args.setdefault('sepal_length_logic',1)
158 | args.setdefault('sepal_width_logic',1)
159 | args.setdefault('petal_length_logic',1)
160 | args.setdefault('petal_width_logic',1)
161 | args.setdefault('logic_select','')
162 | sepal_length_logic = args.pop('sepal_length_logic')
163 | sepal_width_logic = args.pop('sepal_width_logic')
164 | petal_length_logic = args.pop('petal_length_logic')
165 | petal_width_logic = args.pop('petal_width_logic')
166 | logic_select = args.pop('logic_select')
167 | irisDao = IrisDao()
168 | data = irisDao.classifyPredict(sepal_length_logic, sepal_width_logic, petal_length_logic, petal_width_logic, logic_select)
169 | return data
170 |
171 | @ns.route("/show")
172 | class IrisLinearPredictAPI(Resource):
173 | @auth()
174 | @ns.response(IrisFigureSchema(many=False))
175 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
176 | def get(self):
177 | """
178 | Generate Figure
179 | 生成绘图图片,并返回图片路径
180 | """
181 | data = {}
182 | irisDao = IrisDao()
183 | data = irisDao.show()
184 | return data
185 |
--------------------------------------------------------------------------------
/app/modules/iris/schema.py:
--------------------------------------------------------------------------------
1 | """schema
2 |
3 | IRIS Module Response Schema
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | CREATEDATE: 2019-08-23 16:18:40
11 | """
12 |
13 | from flask_restplus_patched import ModelSchema
14 | from flask_marshmallow import base_fields
15 | from .model import *
16 |
17 | class IrisSchema(ModelSchema):
18 | """
19 | IRIS schema
20 | """
21 | class Meta:
22 | model = Iris
23 |
24 | class IrisListPagerSchema(IrisSchema):
25 | """
26 | IRIS pager schema
27 | """
28 | total = base_fields.Integer()
29 | rows = base_fields.Nested(IrisSchema, many=True)
30 | class Meta:
31 | pass
32 |
33 | class IrisPredictSchema(ModelSchema):
34 | """
35 | IRIS pager schema
36 | """
37 | linear_result = base_fields.Float()
38 | classify_result = base_fields.String()
39 | metric = base_fields.Float()
40 | class Meta:
41 | pass
42 |
43 | class IrisFigureSchema(ModelSchema):
44 | """
45 | IRIS pager schema
46 | """
47 | figure_name = base_fields.String()
48 | class Meta:
49 | pass
--------------------------------------------------------------------------------
/app/modules/logs/__init__.py:
--------------------------------------------------------------------------------
1 | """logs
2 |
3 | Init logs module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app.api import api
13 | def init_app(app, **kwargs):
14 | """
15 | Init logs module.
16 | """
17 | from . import resource
18 | api.add_namespace(resource.ns)
--------------------------------------------------------------------------------
/app/modules/logs/model.py:
--------------------------------------------------------------------------------
1 | """model
2 |
3 | Database Table Model
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import db
13 | from app.common.mixin import *
14 |
15 | class Logs(TableMixin, db.Model):
16 | """Model Class"""
17 | __tablename__ = 'logs'
18 | uid = db.Column(db.Integer, index=True, nullable=False)
19 | url = db.Column(db.String(255), nullable=True)
20 | method = db.Column(db.String(10), nullable=True)
21 | referer = db.Column(db.String(255), nullable=True)
22 | path = db.Column(db.String(255), nullable=True)
23 | base_path = db.Column(db.String(255), nullable=True)
24 | route = db.Column(db.String(100), nullable=True)
25 | ip = db.Column(db.String(32), nullable=True)
26 | user_agent = db.Column(db.String(255), nullable=True)
27 | desc = db.Column(db.Text(), nullable=True)
28 |
29 | def __repr__(self):
30 | return (
31 | "<{class_name}("
32 | "id={self.id}, "
33 | "title=\"{self.title}\""
34 | ")>".format(
35 | class_name=self.__class__.__name__,
36 | self=self
37 | )
38 | )
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/modules/logs/param.py:
--------------------------------------------------------------------------------
1 | """param
2 |
3 | Request Parameter
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from flask_marshmallow import base_fields
13 | from marshmallow import validate
14 | from flask_restplus_patched import Parameters, PostFormParameters, JSONParameters
15 | from .schema import *
16 |
17 | class LogsParameters(JSONParameters, LogsSchema):
18 | class Meta(LogsSchema.Meta):
19 | pass
20 |
21 |
--------------------------------------------------------------------------------
/app/modules/logs/resource.py:
--------------------------------------------------------------------------------
1 | """resource
2 |
3 | API Resource Of Logs Module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import db
13 | from flask import current_app,request
14 | from app.common.schema import *
15 | from app.common.param import *
16 | from app.common.wrap import *
17 | from flask_restplus_patched import Resource, Namespace, abort, HTTPStatus
18 | from .model import *
19 | from .schema import *
20 | from .param import *
21 | from sqlalchemy import or_
22 | from .dao import *
23 |
24 | ns = Namespace("logs", description="logs API Resource")
25 |
26 | @ns.route("/")
27 | class LogsAPI(Resource):
28 | @ns.parameters(LogsParameters(dump_only=['id']))
29 | @ns.response(LogsSchema(many=False))
30 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
31 | def post(self, args):
32 | """
33 | add
34 | """
35 | logs = None
36 | logsDao = LogsDao()
37 | try:
38 | logs = logsDao.add(args)
39 | except Exception as e:
40 | abort(500, e)
41 | return logs
42 |
43 | @ns.parameters(LogsParameters())
44 | @ns.response(LogsSchema())
45 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
46 | def put(self, args):
47 | """
48 | edit
49 | """
50 | record = None
51 | logsDao = LogsDao()
52 | try:
53 | record = logsDao.edit(args)
54 | except Exception as e:
55 | abort(500, e)
56 | return record
57 |
58 | @ns.parameters(IDParameters())
59 | @ns.response(LogsSchema())
60 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
61 | def get(self, args):
62 | """
63 | view
64 | """
65 | record = None
66 | logsDao = LogsDao()
67 | id = args.get('id')
68 | record = logsDao.getById(id)
69 | return record
70 |
71 | @auth()
72 | @ns.parameters(IDSParameters())
73 | @ns.response(BasicSchema(many=False))
74 | def delete(self, args):
75 | """
76 | del
77 | """
78 | result = False
79 | ids = args.get('ids')
80 | logsDao = LogsDao()
81 | try:
82 | result = logsDao.delete(ids)
83 | except Exception as e:
84 | abort(500, e)
85 | return {"status":result}
86 |
87 | @ns.route("/list")
88 | class LogsListAPI(Resource):
89 | @auth()
90 | @ns.parameters(PagerParameters())
91 | @ns.response(LogsListPagerSchema(many=False))
92 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
93 | def get(self,args):
94 | """
95 | list
96 | """
97 | data = {}
98 | args.setdefault('search','')
99 | args.setdefault('sort','')
100 | search = args.pop('search')
101 | sort = args.pop('sort')
102 | order = args.pop('order')
103 | offset = args.pop('offset')
104 | limit = args.pop('limit')
105 | logsDao = LogsDao()
106 | data = logsDao.getList(search, sort, order, offset, limit)
107 | return data
108 |
109 | @ns.route("/user")
110 | class UserLogsAPI(Resource):
111 | @ns.parameters(LogsParameters(dump_only=['id']))
112 | @ns.response(LogsSchema(many=False))
113 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
114 | def post(self, args):
115 | """
116 | add
117 | """
118 | logs = None
119 | logsDao = LogsDao()
120 | try:
121 | logs = logsDao.add(args)
122 | except Exception as e:
123 | abort(500, e)
124 | return logs
125 |
126 | @ns.parameters(LogsParameters())
127 | @ns.response(LogsSchema())
128 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
129 | def put(self, args):
130 | """
131 | edit
132 | """
133 | record = None
134 | logsDao = LogsDao()
135 | try:
136 | record = logsDao.edit(args)
137 | except Exception as e:
138 | abort(500, e)
139 | return record
140 |
141 | @ns.parameters(IDParameters())
142 | @ns.response(LogsSchema())
143 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
144 | def get(self, args):
145 | """
146 | view
147 | """
148 | record = None
149 | logsDao = LogsDao()
150 | id = args.get('id')
151 | record = logsDao.getById(id)
152 | return record
153 |
154 | @auth()
155 | @ns.parameters(IDSParameters())
156 | @ns.response(BasicSchema(many=False))
157 | def delete(self, args):
158 | """
159 | del
160 | """
161 | result = False
162 | ids = args.get('ids')
163 | uid = request.uid
164 | logsDao = LogsDao()
165 | try:
166 | result = logsDao.deleteByUid(ids, uid)
167 | except Exception as e:
168 | abort(500, e)
169 | return {"status":result}
170 |
171 | @ns.route("/user/list")
172 | class UserLogsListAPI(Resource):
173 | @auth()
174 | @ns.parameters(PagerParameters())
175 | @ns.response(LogsListPagerSchema(many=False))
176 | @ns.response(code=500,description="Internal Server Exception")
177 | def get(self,args):
178 | """
179 | list
180 | """
181 | data = {}
182 | args.setdefault('search','')
183 | args.setdefault('sort','')
184 | search = args.pop('search')
185 | sort = args.pop('sort')
186 | order = args.pop('order')
187 | offset = args.pop('offset')
188 | limit = args.pop('limit')
189 | logsDao = LogsDao()
190 | uid = request.uid
191 | data = logsDao.getListByUid(search, sort, order, offset, limit, uid)
192 | return data
193 |
194 |
195 |
196 |
--------------------------------------------------------------------------------
/app/modules/logs/schema.py:
--------------------------------------------------------------------------------
1 | """schema
2 |
3 | Response Schema
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from flask_restplus_patched import ModelSchema
13 | from flask_marshmallow import base_fields
14 | from .model import *
15 |
16 | class LogsSchema(ModelSchema):
17 | """
18 | Logs schema .
19 | """
20 |
21 | class Meta:
22 | model = Logs
23 |
24 | class LogsListPagerSchema(ModelSchema):
25 | total = base_fields.Integer()
26 | rows = base_fields.Nested(LogsSchema, many=True)
27 | class Meta:
28 | pass
29 |
30 |
--------------------------------------------------------------------------------
/app/modules/notice_content/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Notice Content module
3 |
4 | PROJECT: BaoAI Backend
5 | AUTHOR: henry <703264459@qq.com>
6 | WEBSITE: http://www.baoai.co
7 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
8 | LICENSE: Apache-2.0
9 | CREATEDATE: 2019-11-30 02:22:26
10 | """
11 |
12 | from app.api import api
13 |
14 | def init_app(app, **kwargs):
15 | """
16 | Init Notice Content module.
17 | """
18 | from . import resource
19 | api.add_namespace(resource.ns)
--------------------------------------------------------------------------------
/app/modules/notice_content/model.py:
--------------------------------------------------------------------------------
1 | """
2 | Notice Content database models
3 |
4 | PROJECT: BaoAI Backend
5 | AUTHOR: henry <703264459@qq.com>
6 | WEBSITE: http://www.baoai.co
7 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
8 | LICENSE: Apache-2.0
9 | CREATEDATE: 2019-11-30 02:22:26
10 | """
11 |
12 | from app import db
13 | from sqlalchemy.schema import FetchedValue
14 | from app.common.mixin import *
15 |
16 | class Notice_content(TableMixin, db.Model):
17 | """
18 | Notice Content database model.
19 | """
20 | __tablename__ = 'notice_content'
21 |
22 | title = db.Column(db.String(255), nullable=False, unique=False, index=True)
23 | icon = db.Column(db.String(100), nullable=True, unique=False, index=False, default='fa fa-circle-o')
24 | content = db.Column(db.Text(), nullable=True, unique=False, index=False)
25 | receiver = db.Column(db.Integer(), nullable=True, unique=False, index=False)
26 | module = db.Column(db.String(100), nullable=True, unique=False, index=False)
27 | reference = db.Column(db.String(255), nullable=True, unique=False, index=False)
28 | reference_params = db.Column(db.String(255), nullable=True, unique=False, index=False)
29 | status = db.Column(db.Boolean(), nullable=False, unique=False, index=True, default=True)
30 | weight = db.Column(db.Integer(), nullable=True, unique=False, index=False, default='0')
31 |
32 |
33 |
34 | def __repr__(self):
35 | return (
36 | "<{class_name}("
37 | "id={self.id}, "
38 | "title=\"{self.title}\""
39 | ")>".format(
40 | class_name=self.__class__.__name__,
41 | self=self
42 | )
43 | )
44 |
--------------------------------------------------------------------------------
/app/modules/notice_content/param.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Notice Content Module Request Parameter
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | CREATEDATE: 2019-11-30 02:22:26
11 | """
12 |
13 | from flask_marshmallow import base_fields
14 | from marshmallow import validate
15 | from flask_restplus_patched import Parameters, PostFormParameters, JSONParameters
16 | from .schema import *
17 | from app.common.param import PagerParameters
18 |
19 | class Notice_contentParameters(JSONParameters, Notice_contentSchema):
20 | """
21 | Notice Content Parameters
22 | """
23 | class Meta(Notice_contentSchema.Meta):
24 | pass
25 |
26 | class ExtendPagerParameters(PagerParameters):
27 | receiver = base_fields.Integer(required=False)
28 |
29 | class ReadStatusParameters(JSONParameters):
30 | id = base_fields.Integer(required=True)
31 | status = base_fields.Boolean(required=True)
--------------------------------------------------------------------------------
/app/modules/notice_content/schema.py:
--------------------------------------------------------------------------------
1 | """schema
2 |
3 | Notice Content Module Response Schema
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | CREATEDATE: 2019-11-30 02:22:26
11 | """
12 |
13 | from flask_restplus_patched import ModelSchema
14 | from flask_marshmallow import base_fields
15 | from .model import *
16 |
17 | class Notice_contentSchema(ModelSchema):
18 | """
19 | Notice Content schema
20 | """
21 | receive_created = base_fields.DateTime()
22 | receive_id = base_fields.Integer()
23 | class Meta:
24 | model = Notice_content
25 |
26 | class Notice_contentListPagerSchema(Notice_contentSchema):
27 | """
28 | Notice Content pager schema
29 | """
30 | total = base_fields.Integer()
31 | rows = base_fields.Nested(Notice_contentSchema, many=True)
32 | class Meta:
33 | pass
--------------------------------------------------------------------------------
/app/modules/notice_content_admin/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | notice_content and admin relation module
3 |
4 | PROJECT: BaoAI Backend
5 | AUTHOR: henry <703264459@qq.com>
6 | WEBSITE: http://www.baoai.co
7 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
8 | LICENSE: Apache-2.0
9 | CREATEDATE: 2019-11-30 02:22:26
10 | """
11 |
12 | from app.api import api
13 | def init_app(app, **kwargs):
14 | """
15 | Init notice_content_admin module.
16 | """
17 | from . import resource
18 | api.add_namespace(resource.ns)
--------------------------------------------------------------------------------
/app/modules/notice_content_admin/dao.py:
--------------------------------------------------------------------------------
1 | """
2 | notice_content and admin relation module Data Access Object
3 |
4 | PROJECT: BaoAI Backend
5 | AUTHOR: henry <703264459@qq.com>
6 | WEBSITE: http://www.baoai.co
7 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
8 | LICENSE: Apache-2.0
9 | CREATEDATE: 2019-11-30 02:22:26
10 | """
11 |
12 | from app import db
13 | from .model import *
14 | from flask import current_app
15 | from sqlalchemy import or_
16 |
17 | class Notice_contentAdminDao(object):
18 | def delete(self, ids):
19 | """delete
20 |
21 | Args:
22 | ids (list): id list
23 |
24 | Returns:
25 | bool: True or False
26 |
27 | """
28 | result = False
29 | if ids:
30 | try:
31 | Notice_contentAdmin.query.filter(Notice_contentAdmin.id.in_(tuple(ids))).delete(synchronize_session=False)
32 | db.session.commit()
33 | except Exception as e:
34 | db.session.rollback()
35 | raise Exception(e)
36 | result = True
37 | return result
38 |
39 | def add(self, args):
40 | """add
41 |
42 | Args:
43 | args (OrderedDict): form args
44 |
45 | Returns:
46 | object: Notice_contentAdmin object
47 |
48 | """
49 | record = None
50 | try:
51 | record = Notice_contentAdmin(**args)
52 | db.session.add(record)
53 | db.session.commit()
54 | except Exception as e:
55 | db.session.rollback()
56 | raise Exception(e)
57 | return record
58 |
59 | def edit(self, args):
60 | """edit
61 |
62 | Args:
63 | args (OrderedDict): form args
64 |
65 | Returns:
66 | object: Notice_contentAdmin object
67 |
68 | """
69 | id = args.pop('id')
70 | record = Notice_contentAdmin.query.get(id)
71 | if record :
72 | try:
73 | for k,v in args.items():
74 | setattr(record,k,v)
75 | db.session.commit()
76 | except Exception as e:
77 | db.session.rollback()
78 | raise Exception(e)
79 | return record
80 |
81 | def getById(self, id):
82 | """view by id
83 |
84 | Args:
85 | id (int): id
86 |
87 | Returns:
88 | object: Notice_content object
89 |
90 | """
91 | record = Notice_contentAdmin.query.get(id)
92 | return record
93 |
94 | def read_edit(self, id, status):
95 | """Read Status Modify # 已读状态修改
96 |
97 | Args:
98 | id (int): notice content id # 内容ID
99 | status (int): status, 1: Already read 0 : unread # 已读状态, 1:已读, 0: 未读
100 |
101 | Returns:
102 | bool: True or False
103 | """
104 | result = False
105 | record = Notice_contentAdmin.query.get(id)
106 | if record :
107 | try:
108 | record.status = status
109 | db.session.commit()
110 | result = True
111 | except Exception as e:
112 | db.session.rollback()
113 | raise Exception(e)
114 | return result
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/app/modules/notice_content_admin/model.py:
--------------------------------------------------------------------------------
1 | """
2 | notice_content and admin relation module database models
3 |
4 | PROJECT: BaoAI Backend
5 | AUTHOR: henry <703264459@qq.com>
6 | WEBSITE: http://www.baoai.co
7 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
8 | LICENSE: Apache-2.0
9 | CREATEDATE: 2019-11-30 02:22:26
10 | """
11 |
12 | from app import db
13 | from app.common.mixin import *
14 |
15 | class Notice_contentAdmin(TableMixin, db.Model):
16 | __tablename__ = 'notice_content_admin'
17 | notice_content_id = db.Column(db.Integer, nullable=False)
18 | admin_id = db.Column(db.Integer, nullable=False)
19 | __table_args__ = (
20 | db.UniqueConstraint('notice_content_id', 'admin_id', name='uix_notice_content_admin_notice_content_id_admin_id'),
21 | )
22 |
23 | def __repr__(self):
24 | return (
25 | "<{class_name}("
26 | "id={self.id}, "
27 | "title=\"{self.title}\""
28 | ")>".format(
29 | class_name=self.__class__.__name__,
30 | self=self
31 | )
32 | )
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/modules/notice_content_admin/param.py:
--------------------------------------------------------------------------------
1 | """
2 | notice_content and admin relation module Request Parameter
3 |
4 | PROJECT: BaoAI Backend
5 | AUTHOR: henry <703264459@qq.com>
6 | WEBSITE: http://www.baoai.co
7 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
8 | LICENSE: Apache-2.0
9 | CREATEDATE: 2019-11-30 02:22:26
10 | """
11 |
12 | from flask_marshmallow import base_fields
13 | from marshmallow import validate
14 | from flask_restplus_patched import Parameters, PostFormParameters, JSONParameters
15 | from .schema import *
16 |
17 | class Notice_contentAdminParameters(JSONParameters, Notice_contentAdminSchema):
18 | class Meta(Notice_contentAdminSchema.Meta):
19 | pass
20 |
--------------------------------------------------------------------------------
/app/modules/notice_content_admin/resource.py:
--------------------------------------------------------------------------------
1 | """
2 | RESTful API notice_content and admin relation module resource
3 |
4 | PROJECT: BaoAI Backend
5 | AUTHOR: henry <703264459@qq.com>
6 | WEBSITE: http://www.baoai.co
7 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
8 | LICENSE: Apache-2.0
9 | CREATEDATE: 2019-11-30 02:22:26
10 | """
11 |
12 | from app import db
13 | from flask import current_app,request
14 | from app.common.status import Status
15 | from app.common.schema import *
16 | from app.common.param import *
17 | from flask_restplus_patched import Resource, Namespace, abort, HTTPStatus
18 | from app.common.result import Result
19 | from .model import *
20 | from .schema import *
21 | from .param import *
22 | from sqlalchemy import or_
23 |
24 | ns = Namespace("Notice_contentAdmin", description="RESTful API Notice_contentAdmin resource")
25 |
--------------------------------------------------------------------------------
/app/modules/notice_content_admin/schema.py:
--------------------------------------------------------------------------------
1 | """
2 | notice_content and admin relation module Response Schema
3 |
4 | PROJECT: BaoAI Backend
5 | AUTHOR: henry <703264459@qq.com>
6 | WEBSITE: http://www.baoai.co
7 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
8 | LICENSE: Apache-2.0
9 | CREATEDATE: 2019-11-30 02:22:26
10 | """
11 |
12 | from flask_restplus_patched import ModelSchema
13 | from flask_marshmallow import base_fields
14 | from .model import *
15 |
16 | class Notice_contentAdminSchema(ModelSchema):
17 | class Meta:
18 | model = Notice_contentAdmin
19 |
--------------------------------------------------------------------------------
/app/modules/profiles/__init__.py:
--------------------------------------------------------------------------------
1 | """profiles
2 |
3 | Init profiles module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app.api import api
13 | def init_app(app, **kwargs):
14 | """
15 | Init profiles module.
16 | """
17 | from . import resource
18 | api.add_namespace(resource.ns)
--------------------------------------------------------------------------------
/app/modules/profiles/dao.py:
--------------------------------------------------------------------------------
1 | """dao
2 |
3 | Data Access Object
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import db
13 | from .model import Profiles
14 | from flask import current_app
15 |
16 | class ProfilesDao(object):
17 | def delete(self, ids):
18 | """delete
19 |
20 | Args:
21 | ids (list): id list
22 |
23 | Returns:
24 | bool: True or False
25 |
26 | """
27 | result = False
28 | if ids:
29 | try:
30 | Profiles.query.filter(Profiles.id.in_(tuple(ids))).delete(synchronize_session=False)
31 | db.session.commit()
32 | except Exception as e:
33 | db.session.rollback()
34 | raise Exception(e)
35 | result = True
36 | return result
37 |
38 | def deleteByUid(self, uids):
39 | """delete by user id
40 |
41 | Args:
42 | ids (list): user id list
43 |
44 | Returns:
45 | bool: True or False
46 |
47 | """
48 | result = False
49 | if ids:
50 | try:
51 | Profiles.query.filter(Profiles.uid.in_(tuple(uids))).delete(synchronize_session=False)
52 | db.session.commit()
53 | except Exception as e:
54 | db.session.rollback()
55 | raise Exception(e)
56 | result = True
57 | return result
58 |
59 | def add(self, args):
60 | """add
61 |
62 | Args:
63 | args (OrderedDict): form args
64 |
65 | Returns:
66 | object: Profiles object
67 |
68 | """
69 | profiles = None
70 | try:
71 | profiles = Profiles(**args)
72 | db.session.add(profiles)
73 | db.session.commit()
74 | except Exception as e:
75 | db.session.rollback()
76 | raise Exception(e)
77 | return profiles
78 |
79 | def edit(self, args):
80 | """edit
81 |
82 | Args:
83 | args (OrderedDict): form args
84 |
85 | Returns:
86 | object: Profiles object
87 |
88 | """
89 | id = args.pop('id')
90 | uid = args.pop('uid')
91 | record = Profiles.query.get(id)
92 | if record :
93 | try:
94 | for k,v in args.items():
95 | setattr(record,k,v)
96 | db.session.commit()
97 | except Exception as e:
98 | db.session.rollback()
99 | raise Exception(e)
100 | return record
101 |
102 | def getById(self, id):
103 | """view by id
104 |
105 | Args:
106 | id (int): id
107 |
108 | Returns:
109 | object: Profiles object
110 |
111 | """
112 | record = Profiles.query.get(id)
113 | return record
114 |
115 | def getByUid(self, uid):
116 | """view by id
117 |
118 | Args:
119 | uid (int): uid
120 |
121 | Returns:
122 | object: Profiles object
123 |
124 | """
125 | record = Profiles.query.filter(Profiles.uid==uid).first()
126 | return record
127 |
128 | def getList(self, search, sort, order, offset, limit):
129 | """view list
130 |
131 | condition: pagination
132 |
133 | Args:
134 | search (str): search field, default is title field
135 | sort (str): sort field
136 | order (str): order type (asc/desc), default is asc
137 | offset (int): Paging offset
138 | limit (int): Maximum number of records per page
139 |
140 | Returns:
141 | object: data, for example: {"rows": lst, "total":pages.total}
142 |
143 | """
144 | data = {}
145 | page = offset // limit + 1
146 | temp_query_obj = None
147 | pages = None
148 | if search.strip() != '' :
149 | temp_query_obj = Profiles.query.filter(Profiles.title.like("%{search}%".format(search=search)))
150 | if sort.strip() != "" and temp_query_obj == None:
151 | temp_query_obj = Profiles.query.order_by(eval("Profiles."+sort+"."+order+"()"))
152 | if sort.strip() != "" and temp_query_obj != None:
153 | temp_query_obj = temp_query_obj.order_by(eval("Profiles."+sort+"."+order+"()"))
154 | if temp_query_obj == None :
155 | pages = Profiles.query.order_by(Profiles.pid.asc()).order_by(Profiles.weight.desc()).paginate(page, limit)
156 | else :
157 | pages = temp_query_obj.paginate(page, limit)
158 | lst = []
159 | if pages:
160 | for item in pages.items:
161 | lst.append(item)
162 | data = {"rows": lst, "total":pages.total}
163 | return data
164 |
165 |
166 |
--------------------------------------------------------------------------------
/app/modules/profiles/model.py:
--------------------------------------------------------------------------------
1 | from app import db
2 | from app.common.mixin import *
3 |
4 | class Profiles(TableMixin, db.Model):
5 | """Model Class"""
6 | __tablename__ = 'profiles'
7 | uid = db.Column(db.Integer, unique=True, index=True, nullable=False)
8 | career = db.Column(db.String(50), nullable=True)
9 | education = db.Column(db.String(255), nullable=True)
10 | location = db.Column(db.String(255), nullable=True)
11 | postcode = db.Column(db.String(32), nullable=True)
12 | mobilephone = db.Column(db.String(32), nullable=True)
13 | tel = db.Column(db.String(32), nullable=True)
14 | skills = db.Column(db.String(255), nullable=True)
15 | motto = db.Column(db.String(255), nullable=True)
16 | firstname = db.Column(db.String(32), nullable=True)
17 | lastname = db.Column(db.String(32), nullable=True)
18 | qq = db.Column(db.String(16), nullable=True)
19 | weixin = db.Column(db.String(32), nullable=True)
20 | weibo = db.Column(db.String(32), nullable=True)
21 | idnumber = db.Column(db.String(18), nullable=True)
22 | birthday = db.Column(db.Date(), nullable=True)
23 | email_notice = db.Column(db.Boolean(), nullable=True, default=False)
24 | sms_notice = db.Column(db.Boolean(), nullable=True, default=False)
25 | weixin_notice = db.Column(db.Boolean(), nullable=True, default=False)
26 |
27 | def __repr__(self):
28 | """Class Serialization"""
29 | return '' % self.uid
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/modules/profiles/param.py:
--------------------------------------------------------------------------------
1 | """param
2 |
3 | Request Parameter
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from flask_marshmallow import base_fields
13 | from marshmallow import validate
14 | from flask_restplus_patched import Parameters, PostFormParameters, JSONParameters
15 | from .schema import *
16 |
17 | class ProfilesParameters(JSONParameters, ProfilesSchema):
18 | class Meta(ProfilesSchema.Meta):
19 | pass
20 |
21 |
--------------------------------------------------------------------------------
/app/modules/profiles/resource.py:
--------------------------------------------------------------------------------
1 | """resource
2 |
3 | API Resource Of Profiles Module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import db
13 | from flask import current_app,request
14 | from flask_restplus._http import HTTPStatus
15 | from app.common.schema import *
16 | from app.common.param import *
17 | from flask_restplus_patched import Resource, Namespace, abort, HTTPStatus
18 | from .model import *
19 | from .schema import *
20 | from .param import *
21 | import random
22 | import string
23 | from sqlalchemy import or_
24 | from .dao import *
25 | from app.common.wrap import auth
26 |
27 | ns = Namespace("profiles", description="profiles API Resource")
28 |
29 | @ns.route("/")
30 | class ProfilesAPI(Resource):
31 | @ns.parameters(ProfilesParameters(dump_only=['id']))
32 | @ns.response(ProfilesSchema(many=False))
33 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
34 | def post(self, args):
35 | """
36 | add
37 | """
38 | profiles = None
39 | profilesDao = ProfilesDao()
40 | try:
41 | profiles = profilesDao.add(args)
42 | except Exception as e:
43 | abort(500, e)
44 | return profiles
45 |
46 | @ns.parameters(ProfilesParameters())
47 | @ns.response(ProfilesSchema())
48 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
49 | def put(self, args):
50 | """
51 | edit
52 | """
53 | record = None
54 | profilesDao = ProfilesDao()
55 | try:
56 | record = profilesDao.edit(args)
57 | except Exception as e:
58 | abort(500, e)
59 | return record
60 |
61 | @auth()
62 | @ns.response(ProfilesSchema())
63 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
64 | def get(self):
65 | """
66 | view
67 | """
68 | record = None
69 | profilesDao = ProfilesDao()
70 | uid = request.uid
71 | record = profilesDao.getByUid(uid)
72 | if not record :
73 | abort(500, 'Profiles Info is Null')
74 | return record
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/app/modules/profiles/schema.py:
--------------------------------------------------------------------------------
1 | """schema
2 |
3 | Response Schema
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from flask_restplus_patched import ModelSchema
13 | from flask_marshmallow import base_fields
14 | from .model import *
15 |
16 | class ProfilesSchema(ModelSchema):
17 | """
18 | Profiles schema .
19 | """
20 | class Meta:
21 | model = Profiles
22 |
23 |
--------------------------------------------------------------------------------
/app/modules/resources/__init__.py:
--------------------------------------------------------------------------------
1 | """resources
2 |
3 | Init resources module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app.api import api
13 | def init_app(app, **kwargs):
14 | """
15 | Init resources module.
16 | """
17 | from . import resource
18 | api.add_namespace(resource.ns)
--------------------------------------------------------------------------------
/app/modules/resources/model.py:
--------------------------------------------------------------------------------
1 | """model
2 |
3 | Database Table Model
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import db
13 | from app.common.mixin import *
14 |
15 | class Resources(TableMixin, db.Model):
16 | __tablename__ = 'resources'
17 | pid = db.Column(db.Integer, nullable=False)
18 | route = db.Column(db.String(255), nullable=False)
19 | icon = db.Column(db.String(128), nullable=False, default='fa fa-circle-o')
20 | remark = db.Column(db.String(255), nullable=True)
21 | ismenu = db.Column(db.Boolean, nullable=False, default=True) # is menu 1 menu 0 feature
22 | weight = db.Column(db.Integer, nullable=False, default=0) # weight , Used for sorting,Descending order
23 | method = db.Column(db.String(20), nullable=False, default='GET') # Routing access method, value: GET POST DELETE PUT OPTION
24 | name = db.Column(db.String(50), nullable=False, unique=True)
25 | link_type = db.Column(db.String(30), nullable=True, unique=False, index=False)
26 | '''
27 | Writing of ui-sref transfer parameters:
28 | ui-sref = "page ({parameter 1: parameter 1 value, parameter 2: parameter 2 value,... })"
29 |
30 | For example:
31 | {module_id:0}
32 | '''
33 | params = db.Column(db.String(255), nullable=True)
34 | locked = db.Column(db.Boolean(), nullable=False, default=False)
35 | # tree
36 | treepath = db.Column(db.String(255), nullable=True) # tree path, for example: .2.120. , 0 does not need to be at the front
37 | treegrade = db.Column(db.Integer, nullable=True) # Tree depth, top level is 0, .2.120. is 2
38 | treepathweight = db.Column(db.String(255), nullable=True) # tree path weight, for example: 2000.2.1500.120. , The weight of node id = 2 is 2000, The weight of node id = 120 is 1500
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/modules/resources/param.py:
--------------------------------------------------------------------------------
1 | """param
2 |
3 | Request Parameter
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from flask_marshmallow import base_fields
13 | from marshmallow import validate
14 | from flask_restplus_patched import Parameters, PostFormParameters, JSONParameters
15 | from .schema import *
16 |
17 | class ResourcesParameters(JSONParameters, ResourcesSchema):
18 | class Meta(ResourcesSchema.Meta):
19 | pass
20 |
--------------------------------------------------------------------------------
/app/modules/resources/resource.py:
--------------------------------------------------------------------------------
1 | """resource
2 |
3 | API Resource Of Resources Module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import db
13 | from flask import current_app,request
14 | from app.common.status import Status
15 | from app.common.schema import *
16 | from app.common.param import *
17 | from flask_restplus_patched import Resource, Namespace, abort, HTTPStatus
18 | from app.common.result import Result
19 | from app.common.wrap import auth
20 | from .model import *
21 | from .schema import *
22 | from .param import *
23 | from .dao import *
24 | from app.modules.roles.model import Roles
25 | from app.modules.adminroles.model import AdminRoles
26 |
27 | ns = Namespace("resources", description="resources API Resource")
28 |
29 | @ns.route("/")
30 | class ResourcesAPI(Resource):
31 | @auth()
32 | @ns.response(ResourcesSchema())
33 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
34 | def get(self):
35 | """
36 | view
37 | """
38 | record = None
39 | resourcesDao = ResourcesDao()
40 | id = request.uid
41 | record = resourcesDao.getById(id)
42 | return record
43 |
44 | @auth()
45 | @ns.parameters(ResourcesParameters(dump_only=['id']))
46 | @ns.response(ResourcesSchema())
47 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR, description="Internal Server Exception")
48 | def post(self, args):
49 | """
50 | add
51 | """
52 | resources = None
53 | resourcesDao = ResourcesDao()
54 | try:
55 | resources = resourcesDao.add(args)
56 | except Exception as e:
57 | abort(500, e)
58 | return resources
59 |
60 | @auth()
61 | @ns.parameters(IDSParameters())
62 | @ns.response(BasicSchema())
63 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
64 | def delete(self, args):
65 | """
66 | del
67 | """
68 | result = False
69 | ids = args.get('ids')
70 | resourcesDao = ResourcesDao()
71 | try:
72 | result = resourcesDao.delete(ids)
73 | except Exception as e:
74 | abort(500, e)
75 | return {"status":result}
76 |
77 | @auth()
78 | @ns.parameters(ResourcesParameters())
79 | @ns.response(ResourcesSchema())
80 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
81 | def put(self, args):
82 | """
83 | edit
84 | """
85 | record = None
86 | resourcesDao = ResourcesDao()
87 | try:
88 | record = resourcesDao.edit(args)
89 | except Exception as e:
90 | abort(500, e)
91 | return record
92 |
93 | @ns.route("/list")
94 | class ResourcesListAPI(Resource):
95 | """
96 | resources module resource list service
97 | """
98 | @auth()
99 | @ns.parameters(PagerParameters())
100 | @ns.response(ResourcesListPagerSchema(many=False))
101 | @ns.response(code=500)
102 | def get(self,args):
103 | """
104 | view list
105 | """
106 | data = {}
107 | args.setdefault('search','')
108 | args.setdefault('sort','')
109 | search = args.pop('search')
110 | sort = args.pop('sort')
111 | order = args.pop('order')
112 | offset = args.pop('offset')
113 | limit = args.pop('limit')
114 | resourcesDao = ResourcesDao()
115 | data = resourcesDao.getList(search, sort, order, offset, limit)
116 | return data
117 |
118 | @ns.route("/menu")
119 | class ResourcesMenuAPI(Resource):
120 |
121 | @ns.response(ResourcesSchema(only=['id', 'pid', 'title', 'name'], many=True))
122 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR, description="Internal Server Exception")
123 | def get(self):
124 | """
125 | get resources menu
126 | condition: Resources.ismenu==1, Resources.status.in_((1,2))
127 | """
128 | record = None
129 | resourcesDao = ResourcesDao()
130 | try:
131 | record = resourcesDao.getMenu()
132 | except Exception as e:
133 | abort(500, e)
134 | return record
135 |
136 | @ns.route("/all")
137 | class ResourcesAllAPI(Resource):
138 | @ns.response(ResourcesSchema(only=['id', 'pid', 'title', 'name'], many=True))
139 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
140 | def get(self):
141 | """
142 | get all resources
143 | condition: Resources.status.in_((1,2))
144 | """
145 | record = None
146 | resourcesDao = ResourcesDao()
147 | try:
148 | record = resourcesDao.getAll()
149 | except Exception as e:
150 | abort(500, e)
151 | return record
152 |
153 | @ns.route("/routes")
154 | class ResourcesRoutesAPI(Resource):
155 | @auth()
156 | @ns.response(ResourcesSchema(many=True))
157 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
158 | def get(self):
159 | """
160 | get corresponding resources by user id
161 | """
162 | record = None
163 | uid = request.uid
164 | resourcesDao = ResourcesDao()
165 | try:
166 | record = resourcesDao.getRoutes(uid)
167 | except Exception as e:
168 | abort(500, e)
169 | return record
170 |
171 | @ns.route("/weight")
172 | class ResourcesWeightAPI(Resource):
173 | @auth()
174 | @ns.response(ResourcesSchema(only=['weight'], many=True))
175 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
176 | def get(self):
177 | """
178 | get weight max value
179 | """
180 | record = None
181 | resourcesDao = ResourcesDao()
182 | record = resourcesDao.getWeightMax()
183 | return record
184 |
185 | @ns.route("/reorder")
186 | class ResourcesReorderAPI(Resource):
187 | @auth()
188 | @ns.response(BasicSchema())
189 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
190 | def get(self):
191 | """
192 | del
193 | """
194 | result = True
195 | resourcesDao = ResourcesDao()
196 | try:
197 | resourcesDao.setTreeInfoWithAllRecord()
198 | except Exception as e:
199 | abort(500, e)
200 | return {"status":result}
--------------------------------------------------------------------------------
/app/modules/resources/schema.py:
--------------------------------------------------------------------------------
1 | """schema
2 |
3 | Response Schema
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from flask_restplus_patched import ModelSchema
13 | from flask_marshmallow import base_fields
14 | from .model import *
15 |
16 | class ResourcesSchema(ModelSchema):
17 | """
18 | Resources schema exposes all fields.
19 | """
20 | class Meta:
21 | model = Resources
22 |
23 | class ResourcesListPagerSchema(ModelSchema):
24 | total = base_fields.Integer()
25 | rows = base_fields.Nested(ResourcesSchema, many=True)
26 | class Meta:
27 | pass
28 |
--------------------------------------------------------------------------------
/app/modules/roles/__init__.py:
--------------------------------------------------------------------------------
1 | """roles
2 |
3 | Init roles module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app.api import api
13 | def init_app(app, **kwargs):
14 | """
15 | Init roles module.
16 | """
17 | from . import resource
18 | api.add_namespace(resource.ns)
--------------------------------------------------------------------------------
/app/modules/roles/model.py:
--------------------------------------------------------------------------------
1 | """model
2 |
3 | Database Table Model
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import db
13 | from app.common.mixin import *
14 |
15 | class Roles(TableMixin, db.Model):
16 | __tablename__ = 'roles'
17 | pid = db.Column(db.Integer, nullable=False)
18 | resources = db.Column(db.Text, nullable=False)
19 | remark = db.Column(db.String(255), nullable=True)
20 | weight = db.Column(db.Integer, nullable=False, default=0) # Weight determines order, inverse order
21 | locked = db.Column(db.Boolean(), nullable=False, default=False)
22 | # tree
23 | treepath = db.Column(db.String(255), nullable=True) # tree path, for example: .2.120. , 0 does not need to be at the front
24 | treegrade = db.Column(db.Integer, nullable=True) # Tree depth, top level is 0, .2.120. is 2
25 | treepathweight = db.Column(db.String(255), nullable=True) # tree path weight, for example: 2000.2.1500.120. , The weight of node id = 2 is 2000, The weight of node id = 120 is 1500
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/modules/roles/param.py:
--------------------------------------------------------------------------------
1 | """param
2 |
3 | Request Parameter
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from flask_marshmallow import base_fields
13 | from marshmallow import validate
14 | from flask_restplus_patched import Parameters, PostFormParameters, JSONParameters
15 | from .schema import *
16 |
17 | class RolesParameters(JSONParameters, RolesSchema):
18 | class Meta(RolesSchema.Meta):
19 | pass
20 |
--------------------------------------------------------------------------------
/app/modules/roles/resource.py:
--------------------------------------------------------------------------------
1 | """resource
2 |
3 | API Resource Of Roles Module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import db
13 | from flask import current_app,request
14 | from app.common.status import Status
15 | from app.common.schema import *
16 | from app.common.param import *
17 | from flask_restplus_patched import Resource, Namespace, abort, HTTPStatus
18 | from app.common.result import Result
19 | from app.common.wrap import auth
20 | from .model import *
21 | from .schema import *
22 | from .param import *
23 | from .dao import *
24 | from sqlalchemy import or_
25 |
26 | ns = Namespace("roles", description="roles API Resource")
27 |
28 | @ns.route("/")
29 | class RolesAPI(Resource):
30 | @auth()
31 | @ns.response(RolesSchema())
32 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
33 | def get(self):
34 | """
35 | view
36 | """
37 | record = None
38 | rolesDao = RolesDao()
39 | id = request.uid
40 | record = rolesDao.getById(id)
41 | return record
42 |
43 | @auth()
44 | @ns.parameters(RolesParameters(dump_only=['id']))
45 | @ns.response(RolesSchema())
46 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
47 | def post(self, args):
48 | """
49 | add
50 | """
51 | roles = None
52 | rolesDao = RolesDao()
53 | try:
54 | roles = rolesDao.add(args)
55 | except Exception as e:
56 | abort(500, e)
57 | return roles
58 |
59 | @auth()
60 | @ns.parameters(IDSParameters())
61 | @ns.response(BasicSchema(many=False))
62 | def delete(self, args):
63 | """
64 | del
65 | """
66 | result = False
67 | ids = args.get('ids')
68 | rolesDao = RolesDao()
69 | try:
70 | result = rolesDao.delete(ids)
71 | except Exception as e:
72 | abort(500, e)
73 | return {"status":result}
74 |
75 | @auth()
76 | @ns.parameters(RolesParameters())
77 | @ns.response(RolesSchema(many=False))
78 | @ns.response(code=HTTPStatus.CONFLICT)
79 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
80 | def put(self, args):
81 | """
82 | edit
83 | """
84 | record = None
85 | rolesDao = RolesDao()
86 | try:
87 | record = rolesDao.edit(args)
88 | except Exception as e:
89 | abort(500, e)
90 | return record
91 |
92 | @ns.route("/list")
93 | class RolesListAPI(Resource):
94 | """
95 | roles module resource list service
96 | """
97 | @auth()
98 | @ns.parameters(PagerParameters())
99 | @ns.response(RolesListPagerSchema(many=False))
100 | @ns.response(code=500)
101 | def get(self,args):
102 | """
103 | view list
104 | """
105 | data = {}
106 | args.setdefault('search','')
107 | args.setdefault('sort','')
108 | search = args.pop('search')
109 | sort = args.pop('sort')
110 | order = args.pop('order')
111 | offset = args.pop('offset')
112 | limit = args.pop('limit')
113 | rolesDao = RolesDao()
114 | data = rolesDao.getList(search, sort, order, offset, limit)
115 | return data
116 |
117 | @ns.route("/menu")
118 | class RolesMenuAPI(Resource):
119 | @auth()
120 | @ns.response(RolesSchema(only=['id', 'pid', 'title'], many=True))
121 | @ns.response(code=HTTPStatus.INTERNAL_SERVER_ERROR)
122 | def get(self):
123 | """view roles list (status=1) # 获取角色菜单列表
124 | """
125 | rolesDao = RolesDao()
126 | menu = rolesDao.getMenu()
127 | return menu
--------------------------------------------------------------------------------
/app/modules/roles/schema.py:
--------------------------------------------------------------------------------
1 | """schema
2 |
3 | Response Schema
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from flask_restplus_patched import ModelSchema
13 | from flask_marshmallow import base_fields
14 | from .model import *
15 |
16 | class RolesSchema(ModelSchema):
17 | class Meta:
18 | model = Roles
19 |
20 | class RolesListPagerSchema(ModelSchema):
21 | total = base_fields.Integer()
22 | rows = base_fields.Nested(RolesSchema, many=True)
23 | class Meta:
24 | pass
25 |
26 |
--------------------------------------------------------------------------------
/app/modules/rolesresources/__init__.py:
--------------------------------------------------------------------------------
1 | """rolesresources
2 |
3 | Init rolesresources module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app.api import api
13 | def init_app(app, **kwargs):
14 | """
15 | Init rolesresources module.
16 | """
17 | from . import resource
18 | api.add_namespace(resource.ns)
--------------------------------------------------------------------------------
/app/modules/rolesresources/dao.py:
--------------------------------------------------------------------------------
1 | """dao
2 |
3 | Data Access Object
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from .model import RolesResources
13 | from app import db
14 |
15 | class RolesResourcesDao(object):
16 | pass
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/modules/rolesresources/model.py:
--------------------------------------------------------------------------------
1 | """model
2 |
3 | Database Table Model
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import db
13 | from app.common.mixin import *
14 |
15 | class RolesResources(TableMixin, db.Model):
16 | __tablename__ = 'roles_resources'
17 | rid = db.Column(db.Integer, nullable=False)
18 | reid = db.Column(db.Integer, nullable=False)
19 | __table_args__ = (
20 | db.UniqueConstraint('rid', 'reid', name='uix_roles_resources_rid_reid'),
21 | )
22 |
23 | def __repr__(self):
24 | return '' % self.title
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/modules/rolesresources/param.py:
--------------------------------------------------------------------------------
1 | """param
2 |
3 | Request Parameter
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from flask_marshmallow import base_fields
13 | from marshmallow import validate
14 | from flask_restplus_patched import Parameters, PostFormParameters, JSONParameters
15 | from app.common.param import BasicPagerParameters, PagerParameters, PagerJSONParameters
16 | from .schema import *
17 |
18 | class AdminRolesParameters(JSONParameters, RolesResourcesSchema):
19 | class Meta(RolesResourcesSchema.Meta):
20 | pass
21 |
22 |
--------------------------------------------------------------------------------
/app/modules/rolesresources/resource.py:
--------------------------------------------------------------------------------
1 | """resource
2 |
3 | API Resource
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from app import db
13 | from flask import current_app,request
14 | from app.common.status import Status
15 | from app.common.schema import *
16 | from app.common.param import *
17 | from flask_restplus_patched import Resource, Namespace, abort, HTTPStatus
18 | from app.common.result import Result
19 | from .model import *
20 | from .schema import *
21 | from .param import *
22 | from sqlalchemy import or_
23 |
24 | ns = Namespace("rolesresources", description="Rolesresources Namespace")
25 |
26 |
--------------------------------------------------------------------------------
/app/modules/rolesresources/schema.py:
--------------------------------------------------------------------------------
1 | """schema
2 |
3 | Response Schema
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 |
12 | from flask_restplus_patched import ModelSchema
13 | from flask_marshmallow import base_fields
14 | from .model import *
15 |
16 | class RolesResourcesSchema(ModelSchema):
17 | class Meta:
18 | model = RolesResources
19 |
20 |
--------------------------------------------------------------------------------
/assets/img/baoai/admin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/assets/img/baoai/admin.png
--------------------------------------------------------------------------------
/assets/img/baoai/ai.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/assets/img/baoai/ai.png
--------------------------------------------------------------------------------
/assets/img/baoai/baoai_avatar_160.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/assets/img/baoai/baoai_avatar_160.png
--------------------------------------------------------------------------------
/assets/img/baoai/baoai_favicon_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/assets/img/baoai/baoai_favicon_16.png
--------------------------------------------------------------------------------
/assets/img/baoai/baoai_favicon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/assets/img/baoai/baoai_favicon_32.png
--------------------------------------------------------------------------------
/assets/img/baoai/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/assets/img/baoai/favicon.ico
--------------------------------------------------------------------------------
/assets/img/baoai/know.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/assets/img/baoai/know.png
--------------------------------------------------------------------------------
/assets/img/baoai/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/assets/img/baoai/logo.png
--------------------------------------------------------------------------------
/assets/img/baoai/quant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/assets/img/baoai/quant.png
--------------------------------------------------------------------------------
/assets/img/baoai/soft.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/assets/img/baoai/soft.jpg
--------------------------------------------------------------------------------
/assets/img/baoai/sys.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/assets/img/baoai/sys.png
--------------------------------------------------------------------------------
/assets/img/baoai/web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/assets/img/baoai/web.png
--------------------------------------------------------------------------------
/db/baoai.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/db/baoai.db
--------------------------------------------------------------------------------
/deploy/ReadME.md:
--------------------------------------------------------------------------------
1 | # deploy文件夹
2 |
3 | 存放本工程的配置文件
4 |
5 | - `gunicorn_config.py`:gunicorn配置文件
6 | - `baoai.ini`:BaoAI API服务的supervisor配置文件
7 | - `beat.ini`:开启celery定时任务调度的supervisor配置文件
8 | - `worker.ini`:启动celery的supervisor配置文件
9 | - `nginx.conf`:前端Web服务器nginx配置文件,包含反向代理后端的API服务
10 |
11 |
12 |
--------------------------------------------------------------------------------
/deploy/baoai.ini:
--------------------------------------------------------------------------------
1 | [program:baoai]
2 | directory = /baoai/BaoAIBack ;启动目录
3 | command = /baoai/BaoAIBack/run_baoai.sh ;启动命令
4 | autostart = true ;在supervisord启动的时候也启动
5 | startsecs = 5 ;启动5秒后没有异常退出,就当作已经正常启动了
6 | autorestart = true ;程序异常退出后自动重启
7 | startretries = 3 ;启动失败自动重试次数,默认是3
8 | user = root ;哪个用户启动
9 | redirect_stderr = true ;把stderr重定向到stdout,默认false
10 | stdout_logfile_maxbytes = 20MB ;stdout日志文件大小,默认50MB
11 | stdout_logfile_backups = 20 ;stdout日志文件备份数
12 | stdout_logfile = /baoai/BaoAIBack/log/baoai.log ;stdout日志文件,需要手动创建目录
--------------------------------------------------------------------------------
/deploy/beat.ini:
--------------------------------------------------------------------------------
1 | [program:beat]
2 | directory = /baoai/BaoAIBack ;启动目录
3 | command = /baoai/BaoAIBack/run_celery_beat.sh ;启动命令
4 | autostart = true ;在supervisord启动的时候也启动
5 | startsecs = 5 ;启动5秒后没有异常退出,就当作已经正常启动了
6 | autorestart = true ;程序异常退出后自动重启
7 | startretries = 3 ;启动失败自动重试次数,默认是3
8 | user = root ;哪个用户启动
9 | redirect_stderr = true ;把stderr重定向到stdout,默认false
10 | stdout_logfile_maxbytes = 20MB ;stdout日志文件大小,默认50MB
11 | stdout_logfile_backups = 20 ;stdout日志文件备份数
12 | stdout_logfile = /baoai/BaoAIBack/log/celery_beat.log ;stdout日志文件,需要手动创建目录
--------------------------------------------------------------------------------
/deploy/gunicorn_config.py:
--------------------------------------------------------------------------------
1 | """
2 | filename: gunicorn_config.py
3 | install : pip3 install gunicorn
4 | sample:
5 | ```shell
6 | #!/bin/sh
7 | basepath=$(cd `dirname $0`; pwd)
8 | cd ${basepath}
9 | venv/bin/gunicorn manage:app -c deploy/gunicorn_config.py
10 | ```
11 | PROJECT: BaoAI Backend
12 | AUTHOR: henry <703264459@qq.com>
13 | WEBSITE: http://www.baoai.co
14 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
15 | LICENSE: Apache-2.0
16 | """
17 |
18 | import sys
19 | import os
20 | import multiprocessing
21 |
22 | # 获取本文件的所在路径
23 | curr_dir = os.path.dirname(os.path.realpath(__file__))
24 | # 获取上级目录的绝对路径
25 | last_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
26 | # 设置Flask App工作目录路径
27 | app_dir = last_dir
28 |
29 | _file_name = os.path.basename(__file__)
30 |
31 | sys.path.insert(0, app_dir)
32 |
33 | # === Server Socket ===
34 | bind = "0.0.0.0:8000" # default: "127.0.0.1:8000"
35 |
36 | # === Server Socket End ===
37 |
38 |
39 |
40 | # === Server Mechanics ===
41 |
42 | chdir = app_dir
43 |
44 | # Switch worker processes to run as this user.
45 | # user =
46 |
47 | # === Server Mechanics End ===
48 |
49 |
50 |
51 | # === Worker Processes ===
52 |
53 | # 进程数
54 | workers = 2
55 | # workers = multiprocessing.cpu_count() * 2 + 1
56 |
57 | # 'gevent' or 'sync', default gevent
58 | worker_class = 'sync'
59 |
60 | # The maximum number of simultaneous clients.
61 | worker_connections = 1000
62 |
63 | # Workers silent for more than this many seconds are killed and restarted.
64 | timeout = 30
65 |
66 | # The maximum number of requests a worker will process before restarting.
67 | max_requests = 2000
68 |
69 | # Timeout for graceful workers restart.
70 | graceful_timeout = 30
71 |
72 | # === Worker Processes End ===
73 |
74 |
75 |
76 | # === Logging ===
77 |
78 | # 错误日志
79 |
80 | # 日志级别,这个日志级别指的是错误日志的级别,而访问日志的级别无法设置
81 | # The granularity of Error log outputs.
82 | loglevel = 'info'
83 |
84 | # The Error log file to write to.
85 | # Using '-' for FILE makes gunicorn log to stderr.
86 | # Changed in version 19.2: Log to stderr by default.
87 | # errorlog = '-'
88 | errorlog = "/dev/null"
89 | # accesslog = os.path.join(curr_dir, "err.err")
90 |
91 | # Redirect stdout/stderr to Error log.
92 | # default: False
93 | # capture_output = False
94 |
95 | # 访问日志
96 |
97 | # 访问日志文件的路径
98 | # The Access log file to write to.
99 | # '-' means log to stdout.
100 | accesslog = '-'
101 | # accesslog = "/dev/null"
102 | # accesslog = os.path.join(curr_dir, "acc.log")
103 |
104 | # 设置gunicorn访问日志格式,错误日志无法设置
105 | # """
106 | # h remote address
107 | # l '-'
108 | # u currently '-', may be user name in future releases
109 | # t date of the request
110 | # r status line (e.g. ``GET / HTTP/1.1``)
111 | # s status
112 | # b response length or '-'
113 | # f referer
114 | # a user agent
115 | # T request time in seconds
116 | # D request time in microseconds
117 | # L request time in decimal seconds
118 | # p process ID
119 | # {Header}i request header
120 | # {Header}o response header
121 | # """
122 | # default: %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"
123 | # access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"'
124 |
125 | # default: False
126 | # syslog = False
127 |
128 | # === Logging End ===
129 |
130 |
131 |
132 | # === Process Naming ===
133 |
134 | # A base to use with setproctitle for process naming.
135 | # proc_name =
136 |
137 | # === Process Naming End ===
138 |
--------------------------------------------------------------------------------
/deploy/nginx.conf:
--------------------------------------------------------------------------------
1 | user www www;
2 | worker_processes auto;
3 |
4 | error_log /data/wwwlogs/error_nginx.log crit;
5 | pid /var/run/nginx.pid;
6 | worker_rlimit_nofile 51200;
7 |
8 | events {
9 | use epoll;
10 | worker_connections 51200;
11 | multi_accept on;
12 | }
13 |
14 | http {
15 | include mime.types;
16 | default_type application/octet-stream;
17 | server_names_hash_bucket_size 128;
18 | client_header_buffer_size 32k;
19 | large_client_header_buffers 4 32k;
20 | client_max_body_size 1024m;
21 | client_body_buffer_size 10m;
22 | sendfile on;
23 | tcp_nopush on;
24 | keepalive_timeout 120;
25 | server_tokens off;
26 | tcp_nodelay on;
27 |
28 | fastcgi_connect_timeout 300;
29 | fastcgi_send_timeout 300;
30 | fastcgi_read_timeout 300;
31 | fastcgi_buffer_size 64k;
32 | fastcgi_buffers 4 64k;
33 | fastcgi_busy_buffers_size 128k;
34 | fastcgi_temp_file_write_size 128k;
35 | fastcgi_intercept_errors on;
36 |
37 | #Gzip Compression
38 | gzip on;
39 | gzip_buffers 16 8k;
40 | gzip_comp_level 6;
41 | gzip_http_version 1.1;
42 | gzip_min_length 256;
43 | gzip_proxied any;
44 | gzip_vary on;
45 | gzip_types
46 | text/xml application/xml application/atom+xml application/rss+xml application/xhtml+xml image/svg+xml
47 | text/javascript application/javascript application/x-javascript
48 | text/x-json application/json application/x-web-app-manifest+json
49 | text/css text/plain text/x-component
50 | font/opentype application/x-font-ttf application/vnd.ms-fontobject
51 | image/x-icon;
52 | gzip_disable "MSIE [1-6]\.(?!.*SV1)";
53 |
54 | ##Brotli Compression
55 | #brotli on;
56 | #brotli_comp_level 6;
57 | #brotli_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;
58 |
59 | ##If you have a lot of static files to serve through Nginx then caching of the files' metadata (not the actual files' contents) can save some latency.
60 | #open_file_cache max=1000 inactive=20s;
61 | #open_file_cache_valid 30s;
62 | #open_file_cache_min_uses 2;
63 | #open_file_cache_errors on;
64 |
65 | ######################## default ############################
66 | upstream node {
67 | server 127.0.0.1:8000;
68 | }
69 | server {
70 | listen 80;
71 | server_name _;
72 | access_log /data/wwwlogs/access_nginx.log combined;
73 | root /baoai/baoaifront;
74 | index index.html index.htm index.php;
75 | if ($request_uri ~ ^/(static|login|register|password|app|api)) {
76 | set $cookie_nocache 1;
77 | }
78 | location / {
79 | index index.html index.htm index.php;
80 | try_files $uri $uri/ /index.html =404;
81 | # proxy_cache cache;
82 | # proxy_cache_valid 200 304 12h;
83 | # proxy_cache_valid any 10m;
84 | # add_header Nginx-Cache "$upstream_cache_status";
85 | # proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
86 | # proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
87 | # proxy_no_cache $http_pargma $http_authorization;
88 | }
89 |
90 | location ^~ /static/ {
91 | proxy_pass http://node;
92 | proxy_set_header Host $http_host;
93 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
94 | # proxy_cache cache;
95 | # proxy_cache_valid 200 304 12h;
96 | # proxy_cache_valid any 10m;
97 | # add_header Nginx-Cache "$upstream_cache_status";
98 | # proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
99 | # proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
100 | # proxy_no_cache $http_pargma $http_authorization;
101 | }
102 |
103 | location ^~ /api/ { # ƥ����??host/api/ ��url
104 | proxy_pass http://node;
105 | proxy_set_header Host $host;
106 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
107 | # proxy_cache cache;
108 | # proxy_cache_valid 200 304 12h;
109 | # proxy_cache_valid any 10m;
110 | # add_header Nginx-Cache "$upstream_cache_status";
111 | # proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
112 | # proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
113 | # proxy_no_cache $http_pargma $http_authorization;
114 | }
115 | #error_page 404 /404.html;
116 | #error_page 502 /502.html;
117 | location /nginx_status {
118 | stub_status on;
119 | access_log off;
120 | allow 127.0.0.1;
121 | deny all;
122 | }
123 |
124 | # location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ {
125 | # expires 30d;
126 | # access_log off;
127 | # }
128 | # location ~ .*\.(js|css)?$ {
129 | # expires 7d;
130 | # access_log off;
131 | # }
132 | location ~ ^/(\.user.ini|\.ht|\.git|\.svn|\.project|LICENSE|README.md) {
133 | deny all;
134 | }
135 | }
136 | ########################## vhost #############################
137 | include vhost/*.conf;
138 | }
139 |
--------------------------------------------------------------------------------
/deploy/worker.ini:
--------------------------------------------------------------------------------
1 | [program:worker]
2 | directory = /baoai/BaoAIBack ;启动目录
3 | command = /baoai/BaoAIBack/run_celery_worker.sh ;启动命令
4 | autostart = true ;在supervisord启动的时候也启动
5 | startsecs = 5 ;启动5秒后没有异常退出,就当作已经正常启动了
6 | autorestart = true ;程序异常退出后自动重启
7 | startretries = 3 ;启动失败自动重试次数,默认是3
8 | user = root ;哪个用户启动
9 | redirect_stderr = true ;把stderr重定向到stdout,默认false
10 | stdout_logfile_maxbytes = 20MB ;stdout日志文件大小,默认50MB
11 | stdout_logfile_backups = 20 ;stdout日志文件备份数
12 | stdout_logfile = /baoai/BaoAIBack/log/celery_worker.log ;stdout日志文件,需要手动创建目录
--------------------------------------------------------------------------------
/flask_restplus/__about__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | __version__ = '0.11.0'
3 | __description__ = 'Fully featured framework for fast, easy and documented API development with Flask'
4 |
--------------------------------------------------------------------------------
/flask_restplus/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import absolute_import
3 |
4 | from . import fields, reqparse, apidoc, inputs, cors
5 | from .api import Api # noqa
6 | from .marshalling import marshal, marshal_with, marshal_with_field # noqa
7 | from .mask import Mask
8 | from .model import Model, OrderedModel, SchemaModel # noqa
9 | from .namespace import Namespace # noqa
10 | from .resource import Resource # noqa
11 | from .errors import abort, RestError, SpecsError, ValidationError
12 | from .swagger import Swagger
13 | from .__about__ import __version__, __description__
14 |
15 | __all__ = (
16 | '__version__',
17 | '__description__',
18 | 'Api',
19 | 'Resource',
20 | 'apidoc',
21 | 'marshal',
22 | 'marshal_with',
23 | 'marshal_with_field',
24 | 'Mask',
25 | 'Model',
26 | 'OrderedModel',
27 | 'SchemaModel',
28 | 'abort',
29 | 'cors',
30 | 'fields',
31 | 'inputs',
32 | 'reqparse',
33 | 'RestError',
34 | 'SpecsError',
35 | 'Swagger',
36 | 'ValidationError',
37 | )
38 |
--------------------------------------------------------------------------------
/flask_restplus/_http.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | This file is backported from Python 3.5 http built-in module.
4 | """
5 |
6 | from enum import IntEnum
7 |
8 |
9 | class HTTPStatus(IntEnum):
10 | """HTTP status codes and reason phrases
11 |
12 | Status codes from the following RFCs are all observed:
13 |
14 | * RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616
15 | * RFC 6585: Additional HTTP Status Codes
16 | * RFC 3229: Delta encoding in HTTP
17 | * RFC 4918: HTTP Extensions for WebDAV, obsoletes 2518
18 | * RFC 5842: Binding Extensions to WebDAV
19 | * RFC 7238: Permanent Redirect
20 | * RFC 2295: Transparent Content Negotiation in HTTP
21 | * RFC 2774: An HTTP Extension Framework
22 | """
23 | def __new__(cls, value, phrase, description=''):
24 | obj = int.__new__(cls, value)
25 | obj._value_ = value
26 |
27 | obj.phrase = phrase
28 | obj.description = description
29 | return obj
30 |
31 | def __str__(self):
32 | return str(self.value)
33 |
34 | # informational
35 | CONTINUE = 100, 'Continue', 'Request received, please continue'
36 | SWITCHING_PROTOCOLS = (101, 'Switching Protocols',
37 | 'Switching to new protocol; obey Upgrade header')
38 | PROCESSING = 102, 'Processing'
39 |
40 | # success
41 | OK = 200, 'OK', 'Request fulfilled, document follows'
42 | CREATED = 201, 'Created', 'Document created, URL follows'
43 | ACCEPTED = (202, 'Accepted',
44 | 'Request accepted, processing continues off-line')
45 | NON_AUTHORITATIVE_INFORMATION = (203,
46 | 'Non-Authoritative Information', 'Request fulfilled from cache')
47 | NO_CONTENT = 204, 'No Content', 'Request fulfilled, nothing follows'
48 | RESET_CONTENT = 205, 'Reset Content', 'Clear input form for further input'
49 | PARTIAL_CONTENT = 206, 'Partial Content', 'Partial content follows'
50 | MULTI_STATUS = 207, 'Multi-Status'
51 | ALREADY_REPORTED = 208, 'Already Reported'
52 | IM_USED = 226, 'IM Used'
53 |
54 | # redirection
55 | MULTIPLE_CHOICES = (300, 'Multiple Choices',
56 | 'Object has several resources -- see URI list')
57 | MOVED_PERMANENTLY = (301, 'Moved Permanently',
58 | 'Object moved permanently -- see URI list')
59 | FOUND = 302, 'Found', 'Object moved temporarily -- see URI list'
60 | SEE_OTHER = 303, 'See Other', 'Object moved -- see Method and URL list'
61 | NOT_MODIFIED = (304, 'Not Modified',
62 | 'Document has not changed since given time')
63 | USE_PROXY = (305, 'Use Proxy',
64 | 'You must use proxy specified in Location to access this resource')
65 | TEMPORARY_REDIRECT = (307, 'Temporary Redirect',
66 | 'Object moved temporarily -- see URI list')
67 | PERMANENT_REDIRECT = (308, 'Permanent Redirect',
68 | 'Object moved temporarily -- see URI list')
69 |
70 | # client error
71 | BAD_REQUEST = (400, 'Bad Request',
72 | 'Bad request syntax or unsupported method')
73 | UNAUTHORIZED = (401, 'Unauthorized',
74 | 'No permission -- see authorization schemes')
75 | PAYMENT_REQUIRED = (402, 'Payment Required',
76 | 'No payment -- see charging schemes')
77 | FORBIDDEN = (403, 'Forbidden',
78 | 'Request forbidden -- authorization will not help')
79 | NOT_FOUND = (404, 'Not Found',
80 | 'Nothing matches the given URI')
81 | METHOD_NOT_ALLOWED = (405, 'Method Not Allowed',
82 | 'Specified method is invalid for this resource')
83 | NOT_ACCEPTABLE = (406, 'Not Acceptable',
84 | 'URI not available in preferred format')
85 | PROXY_AUTHENTICATION_REQUIRED = (407,
86 | 'Proxy Authentication Required',
87 | 'You must authenticate with this proxy before proceeding')
88 | REQUEST_TIMEOUT = (408, 'Request Timeout',
89 | 'Request timed out; try again later')
90 | CONFLICT = 409, 'Conflict', 'Request conflict'
91 | GONE = (410, 'Gone',
92 | 'URI no longer exists and has been permanently removed')
93 | LENGTH_REQUIRED = (411, 'Length Required',
94 | 'Client must specify Content-Length')
95 | PRECONDITION_FAILED = (412, 'Precondition Failed',
96 | 'Precondition in headers is false')
97 | REQUEST_ENTITY_TOO_LARGE = (413, 'Request Entity Too Large',
98 | 'Entity is too large')
99 | REQUEST_URI_TOO_LONG = (414, 'Request-URI Too Long',
100 | 'URI is too long')
101 | UNSUPPORTED_MEDIA_TYPE = (415, 'Unsupported Media Type',
102 | 'Entity body in unsupported format')
103 | REQUESTED_RANGE_NOT_SATISFIABLE = (416,
104 | 'Requested Range Not Satisfiable',
105 | 'Cannot satisfy request range')
106 | EXPECTATION_FAILED = (417, 'Expectation Failed',
107 | 'Expect condition could not be satisfied')
108 | UNPROCESSABLE_ENTITY = 422, 'Unprocessable Entity'
109 | LOCKED = 423, 'Locked'
110 | FAILED_DEPENDENCY = 424, 'Failed Dependency'
111 | UPGRADE_REQUIRED = 426, 'Upgrade Required'
112 | PRECONDITION_REQUIRED = (428, 'Precondition Required',
113 | 'The origin server requires the request to be conditional')
114 | TOO_MANY_REQUESTS = (429, 'Too Many Requests',
115 | 'The user has sent too many requests in '
116 | 'a given amount of time ("rate limiting")')
117 | REQUEST_HEADER_FIELDS_TOO_LARGE = (431,
118 | 'Request Header Fields Too Large',
119 | 'The server is unwilling to process the request because its header '
120 | 'fields are too large')
121 |
122 | # server errors
123 | INTERNAL_SERVER_ERROR = (500, 'Internal Server Error',
124 | 'Server got itself in trouble')
125 | NOT_IMPLEMENTED = (501, 'Not Implemented',
126 | 'Server does not support this operation')
127 | BAD_GATEWAY = (502, 'Bad Gateway',
128 | 'Invalid responses from another server/proxy')
129 | SERVICE_UNAVAILABLE = (503, 'Service Unavailable',
130 | 'The server cannot process the request due to a high load')
131 | GATEWAY_TIMEOUT = (504, 'Gateway Timeout',
132 | 'The gateway server did not receive a timely response')
133 | HTTP_VERSION_NOT_SUPPORTED = (505, 'HTTP Version Not Supported',
134 | 'Cannot fulfill request')
135 | VARIANT_ALSO_NEGOTIATES = 506, 'Variant Also Negotiates'
136 | INSUFFICIENT_STORAGE = 507, 'Insufficient Storage'
137 | LOOP_DETECTED = 508, 'Loop Detected'
138 | NOT_EXTENDED = 510, 'Not Extended'
139 | NETWORK_AUTHENTICATION_REQUIRED = (511,
140 | 'Network Authentication Required',
141 | 'The client needs to authenticate to gain network access')
142 |
--------------------------------------------------------------------------------
/flask_restplus/apidoc.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from flask import url_for, Blueprint, render_template
5 |
6 |
7 | class Apidoc(Blueprint):
8 | '''
9 | Allow to know if the blueprint has already been registered
10 | until https://github.com/mitsuhiko/flask/pull/1301 is merged
11 | '''
12 | def __init__(self, *args, **kwargs):
13 | self.registered = False
14 | super(Apidoc, self).__init__(*args, **kwargs)
15 |
16 | def register(self, *args, **kwargs):
17 | super(Apidoc, self).register(*args, **kwargs)
18 | self.registered = True
19 |
20 |
21 | apidoc = Apidoc('restplus_doc', __name__,
22 | template_folder='templates',
23 | static_folder='static',
24 | static_url_path='/swaggerui',
25 | )
26 |
27 |
28 | @apidoc.add_app_template_global
29 | def swagger_static(filename):
30 | return url_for('restplus_doc.static', filename=filename)
31 |
32 |
33 | def ui_for(api):
34 | '''Render a SwaggerUI for a given API'''
35 | return render_template('swagger-ui.html', title=api.title,
36 | specs_url=api.specs_url)
37 |
--------------------------------------------------------------------------------
/flask_restplus/cors.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from datetime import timedelta
5 | from flask import make_response, request, current_app
6 | from functools import update_wrapper
7 |
8 |
9 | def crossdomain(origin=None, methods=None, headers=None, expose_headers=None,
10 | max_age=21600, attach_to_all=True,
11 | automatic_options=True, credentials=False):
12 | """
13 | http://flask.pocoo.org/snippets/56/
14 | """
15 | if methods is not None:
16 | methods = ', '.join(sorted(x.upper() for x in methods))
17 | if headers is not None and not isinstance(headers, str):
18 | headers = ', '.join(x.upper() for x in headers)
19 | if expose_headers is not None and not isinstance(expose_headers, str):
20 | expose_headers = ', '.join(x.upper() for x in expose_headers)
21 | if not isinstance(origin, str):
22 | origin = ', '.join(origin)
23 | if isinstance(max_age, timedelta):
24 | max_age = max_age.total_seconds()
25 |
26 | def get_methods():
27 | if methods is not None:
28 | return methods
29 |
30 | options_resp = current_app.make_default_options_response()
31 | return options_resp.headers['allow']
32 |
33 | def decorator(f):
34 | def wrapped_function(*args, **kwargs):
35 | if automatic_options and request.method == 'OPTIONS':
36 | resp = current_app.make_default_options_response()
37 | else:
38 | resp = make_response(f(*args, **kwargs))
39 | if not attach_to_all and request.method != 'OPTIONS':
40 | return resp
41 |
42 | h = resp.headers
43 |
44 | h['Access-Control-Allow-Origin'] = origin
45 | h['Access-Control-Allow-Methods'] = get_methods()
46 | h['Access-Control-Max-Age'] = str(max_age)
47 | if credentials:
48 | h['Access-Control-Allow-Credentials'] = 'true'
49 | if headers is not None:
50 | h['Access-Control-Allow-Headers'] = headers
51 | if expose_headers is not None:
52 | h['Access-Control-Expose-Headers'] = expose_headers
53 | return resp
54 |
55 | f.provide_automatic_options = False
56 | return update_wrapper(wrapped_function, f)
57 | return decorator
58 |
--------------------------------------------------------------------------------
/flask_restplus/errors.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | import flask
5 |
6 | from werkzeug.exceptions import HTTPException
7 |
8 | from ._http import HTTPStatus
9 |
10 | __all__ = (
11 | 'abort',
12 | 'RestError',
13 | 'ValidationError',
14 | 'SpecsError',
15 | )
16 |
17 |
18 | def abort(code=HTTPStatus.INTERNAL_SERVER_ERROR, message=None, **kwargs):
19 | '''
20 | Properly abort the current request.
21 |
22 | Raise a `HTTPException` for the given status `code`.
23 | Attach any keyword arguments to the exception for later processing.
24 |
25 | :param int code: The associated HTTP status code
26 | :param str message: An optional details message
27 | :param kwargs: Any additional data to pass to the error payload
28 | :raise HTTPException:
29 | '''
30 | try:
31 | flask.abort(code)
32 | except HTTPException as e:
33 | if message:
34 | kwargs['message'] = str(message)
35 | if kwargs:
36 | e.data = kwargs
37 | raise
38 |
39 |
40 | class RestError(Exception):
41 | '''Base class for all Flask-Restplus Errors'''
42 | def __init__(self, msg):
43 | self.msg = msg
44 |
45 | def __str__(self):
46 | return self.msg
47 |
48 |
49 | class ValidationError(RestError):
50 | '''An helper class for validation errors.'''
51 | pass
52 |
53 |
54 | class SpecsError(RestError):
55 | '''An helper class for incoherent specifications.'''
56 | pass
57 |
--------------------------------------------------------------------------------
/flask_restplus/mask.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals, absolute_import
3 |
4 | import logging
5 | import re
6 | import six
7 |
8 | from collections import OrderedDict
9 | from inspect import isclass
10 |
11 | from .errors import RestError
12 |
13 | log = logging.getLogger(__name__)
14 |
15 | LEXER = re.compile(r'\{|\}|\,|[\w_:\-\*]+')
16 |
17 |
18 | class MaskError(RestError):
19 | '''Raised when an error occurs on mask'''
20 | pass
21 |
22 |
23 | class ParseError(MaskError):
24 | '''Raised when the mask parsing failed'''
25 | pass
26 |
27 |
28 | class Mask(OrderedDict):
29 | '''
30 | Hold a parsed mask.
31 |
32 | :param str|dict|Mask mask: A mask, parsed or not
33 | :param bool skip: If ``True``, missing fields won't appear in result
34 | '''
35 | def __init__(self, mask=None, skip=False, **kwargs):
36 | self.skip = skip
37 | if isinstance(mask, six.string_types):
38 | super(Mask, self).__init__()
39 | self.parse(mask)
40 | elif isinstance(mask, (dict, OrderedDict)):
41 | super(Mask, self).__init__(mask, **kwargs)
42 | else:
43 | self.skip = skip
44 | super(Mask, self).__init__(**kwargs)
45 |
46 | def parse(self, mask):
47 | '''
48 | Parse a fields mask.
49 | Expect something in the form::
50 |
51 | {field,nested{nested_field,another},last}
52 |
53 | External brackets are optionals so it can also be written::
54 |
55 | field,nested{nested_field,another},last
56 |
57 | All extras characters will be ignored.
58 |
59 | :param str mask: the mask string to parse
60 | :raises ParseError: when a mask is unparseable/invalid
61 |
62 | '''
63 | if not mask:
64 | return
65 |
66 | mask = self.clean(mask)
67 | fields = self
68 | previous = None
69 | stack = []
70 |
71 | for token in LEXER.findall(mask):
72 | if token == '{':
73 | if previous not in fields:
74 | raise ParseError('Unexpected opening bracket')
75 | fields[previous] = Mask(skip=self.skip)
76 | stack.append(fields)
77 | fields = fields[previous]
78 | elif token == '}':
79 | if not stack:
80 | raise ParseError('Unexpected closing bracket')
81 | fields = stack.pop()
82 | elif token == ',':
83 | if previous in (',', '{', None):
84 | raise ParseError('Unexpected comma')
85 | else:
86 | fields[token] = True
87 |
88 | previous = token
89 |
90 | if stack:
91 | raise ParseError('Missing closing bracket')
92 |
93 | def clean(self, mask):
94 | '''Remove unecessary characters'''
95 | mask = mask.replace('\n', '').strip()
96 | # External brackets are optional
97 | if mask[0] == '{':
98 | if mask[-1] != '}':
99 | raise ParseError('Missing closing bracket')
100 | mask = mask[1:-1]
101 | return mask
102 |
103 | def apply(self, data):
104 | '''
105 | Apply a fields mask to the data.
106 |
107 | :param data: The data or model to apply mask on
108 | :raises MaskError: when unable to apply the mask
109 |
110 | '''
111 | from . import fields
112 | # Should handle lists
113 | if isinstance(data, (list, tuple, set)):
114 | return [self.apply(d) for d in data]
115 | elif isinstance(data, (fields.Nested, fields.List, fields.Polymorph)):
116 | return data.clone(self)
117 | elif type(data) == fields.Raw:
118 | return fields.Raw(default=data.default, attribute=data.attribute, mask=self)
119 | elif data == fields.Raw:
120 | return fields.Raw(mask=self)
121 | elif isinstance(data, fields.Raw) or isclass(data) and issubclass(data, fields.Raw):
122 | # Not possible to apply a mask on these remaining fields types
123 | raise MaskError('Mask is inconsistent with model')
124 | # Should handle objects
125 | elif (not isinstance(data, (dict, OrderedDict)) and hasattr(data, '__dict__')):
126 | data = data.__dict__
127 |
128 | return self.filter_data(data)
129 |
130 | def filter_data(self, data):
131 | '''
132 | Handle the data filtering given a parsed mask
133 |
134 | :param dict data: the raw data to filter
135 | :param list mask: a parsed mask tofilter against
136 | :param bool skip: whether or not to skip missing fields
137 |
138 | '''
139 | out = {}
140 | for field, content in six.iteritems(self):
141 | if field == '*':
142 | continue
143 | elif isinstance(content, Mask):
144 | nested = data.get(field, None)
145 | if self.skip and nested is None:
146 | continue
147 | elif nested is None:
148 | out[field] = None
149 | else:
150 | out[field] = content.apply(nested)
151 | elif self.skip and field not in data:
152 | continue
153 | else:
154 | out[field] = data.get(field, None)
155 |
156 | if '*' in self.keys():
157 | for key, value in six.iteritems(data):
158 | if key not in out:
159 | out[key] = value
160 | return out
161 |
162 | def __str__(self):
163 | return '{{{0}}}'.format(','.join([
164 | ''.join((k, str(v))) if isinstance(v, Mask) else k
165 | for k, v in six.iteritems(self)
166 | ]))
167 |
168 |
169 | def apply(data, mask, skip=False):
170 | '''
171 | Apply a fields mask to the data.
172 |
173 | :param data: The data or model to apply mask on
174 | :param str|Mask mask: the mask (parsed or not) to apply on data
175 | :param bool skip: If rue, missing field won't appear in result
176 | :raises MaskError: when unable to apply the mask
177 |
178 | '''
179 | return Mask(mask, skip).apply(data)
180 |
--------------------------------------------------------------------------------
/flask_restplus/representations.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals, absolute_import
3 |
4 | try:
5 | from ujson import dumps
6 | except ImportError:
7 | from json import dumps
8 |
9 | from flask import make_response, current_app
10 |
11 |
12 | def output_json(data, code, headers=None):
13 | '''Makes a Flask response with a JSON encoded body'''
14 |
15 | settings = current_app.config.get('RESTPLUS_JSON', {})
16 |
17 | # If we're in debug mode, and the indent is not set, we set it to a
18 | # reasonable value here. Note that this won't override any existing value
19 | # that was set.
20 | if current_app.debug:
21 | settings.setdefault('indent', 4)
22 |
23 | # always end the json dumps with a new line
24 | # see https://github.com/mitsuhiko/flask/pull/1262
25 | dumped = dumps(data, **settings) + "\n"
26 |
27 | resp = make_response(dumped, code)
28 | resp.headers.extend(headers or {})
29 | return resp
30 |
--------------------------------------------------------------------------------
/flask_restplus/resource.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from flask import request
5 | from flask.views import MethodView
6 | from werkzeug.wrappers import BaseResponse
7 |
8 | from .model import ModelBase
9 |
10 | from .utils import unpack
11 |
12 |
13 | class Resource(MethodView):
14 | '''
15 | Represents an abstract RESTPlus resource.
16 |
17 | Concrete resources should extend from this class
18 | and expose methods for each supported HTTP method.
19 | If a resource is invoked with an unsupported HTTP method,
20 | the API will return a response with status 405 Method Not Allowed.
21 | Otherwise the appropriate method is called and passed all arguments
22 | from the url rule used when adding the resource to an Api instance.
23 | See :meth:`~flask_restplus.Api.add_resource` for details.
24 | '''
25 |
26 | representations = None
27 | method_decorators = []
28 |
29 | def __init__(self, api=None, *args, **kwargs):
30 | self.api = api
31 |
32 | def dispatch_request(self, *args, **kwargs):
33 | # Taken from flask
34 | meth = getattr(self, request.method.lower(), None)
35 | if meth is None and request.method == 'HEAD':
36 | meth = getattr(self, 'get', None)
37 | assert meth is not None, 'Unimplemented method %r' % request.method
38 |
39 | for decorator in self.method_decorators:
40 | meth = decorator(meth)
41 |
42 | self.validate_payload(meth)
43 |
44 | resp = meth(*args, **kwargs)
45 |
46 | if isinstance(resp, BaseResponse):
47 | return resp
48 |
49 | representations = self.representations or {}
50 |
51 | mediatype = request.accept_mimetypes.best_match(representations, default=None)
52 | if mediatype in representations:
53 | data, code, headers = unpack(resp)
54 | resp = representations[mediatype](data, code, headers)
55 | resp.headers['Content-Type'] = mediatype
56 | return resp
57 |
58 | return resp
59 |
60 | def __validate_payload(self, expect, collection=False):
61 | '''
62 | :param ModelBase expect: the expected model for the input payload
63 | :param bool collection: False if a single object of a resource is
64 | expected, True if a collection of objects of a resource is expected.
65 | '''
66 | # TODO: proper content negotiation
67 | data = request.get_json()
68 | if collection:
69 | data = data if isinstance(data, list) else [data]
70 | for obj in data:
71 | expect.validate(obj, self.api.refresolver, self.api.format_checker)
72 | else:
73 | expect.validate(data, self.api.refresolver, self.api.format_checker)
74 |
75 | def validate_payload(self, func):
76 | '''Perform a payload validation on expected model if necessary'''
77 | if getattr(func, '__apidoc__', False) is not False:
78 | doc = func.__apidoc__
79 | validate = doc.get('validate', None)
80 | validate = validate if validate is not None else self.api._validate
81 | if validate:
82 | for expect in doc.get('expect', []):
83 | # TODO: handle third party handlers
84 | if isinstance(expect, list) and len(expect) == 1:
85 | if isinstance(expect[0], ModelBase):
86 | self.__validate_payload(expect[0], collection=True)
87 | if isinstance(expect, ModelBase):
88 | self.__validate_payload(expect, collection=False)
89 |
--------------------------------------------------------------------------------
/flask_restplus/static/droid-sans.css:
--------------------------------------------------------------------------------
1 | /* droid-sans-400normal - latin */
2 | @font-face {
3 | font-family: 'Droid Sans';
4 | font-style: normal;
5 | font-display: swap;
6 | font-weight: 400;
7 | src:
8 | local('Droid Sans Regular '),
9 | local('Droid Sans-Regular'),
10 | url('./files/droid-sans-latin-400.woff2') format('woff2'), /* Super Modern Browsers */
11 | url('./files/droid-sans-latin-400.woff') format('woff'); /* Modern Browsers */
12 | }
13 |
14 | /* droid-sans-700normal - latin */
15 | @font-face {
16 | font-family: 'Droid Sans';
17 | font-style: normal;
18 | font-display: swap;
19 | font-weight: 700;
20 | src:
21 | local('Droid Sans Bold '),
22 | local('Droid Sans-Bold'),
23 | url('./files/droid-sans-latin-700.woff2') format('woff2'), /* Super Modern Browsers */
24 | url('./files/droid-sans-latin-700.woff') format('woff'); /* Modern Browsers */
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/flask_restplus/static/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/flask_restplus/static/favicon-16x16.png
--------------------------------------------------------------------------------
/flask_restplus/static/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/flask_restplus/static/favicon-32x32.png
--------------------------------------------------------------------------------
/flask_restplus/static/files/.npmignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/flask_restplus/static/files/.npmignore
--------------------------------------------------------------------------------
/flask_restplus/static/files/droid-sans-latin-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/flask_restplus/static/files/droid-sans-latin-400.woff
--------------------------------------------------------------------------------
/flask_restplus/static/files/droid-sans-latin-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/flask_restplus/static/files/droid-sans-latin-400.woff2
--------------------------------------------------------------------------------
/flask_restplus/static/files/droid-sans-latin-700.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/flask_restplus/static/files/droid-sans-latin-700.woff
--------------------------------------------------------------------------------
/flask_restplus/static/files/droid-sans-latin-700.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/flask_restplus/static/files/droid-sans-latin-700.woff2
--------------------------------------------------------------------------------
/flask_restplus/static/swagger-ui.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"swagger-ui.css","sourceRoot":""}
--------------------------------------------------------------------------------
/flask_restplus/templates/swagger-ui-css.html:
--------------------------------------------------------------------------------
1 | {#
3 |
5 |
7 |
9 |
11 | #}
12 |
13 |
14 |
34 |
--------------------------------------------------------------------------------
/flask_restplus/templates/swagger-ui-libs.html:
--------------------------------------------------------------------------------
1 | {#
2 | {% if config.SWAGGER_UI_LANGUAGES %}
3 |
4 | {% for lang in config.SWAGGER_UI_LANGUAGES %}
5 | {% set filename = 'lang/{0}.js'.format(lang) %}
6 |
7 | {% endfor%}
8 | {% endif %}
9 | #}
10 |
11 |
12 |
--------------------------------------------------------------------------------
/flask_restplus/templates/swagger-ui.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ title }}
5 | {% include 'swagger-ui-css.html' %}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
46 |
47 |
48 |
49 | {% include 'swagger-ui-libs.html' %}
50 |
77 |
78 |
79 |
84 |
--------------------------------------------------------------------------------
/flask_restplus/utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | import re
5 |
6 | from collections import OrderedDict
7 | from copy import deepcopy
8 | from six import iteritems
9 |
10 | from ._http import HTTPStatus
11 |
12 |
13 | FIRST_CAP_RE = re.compile('(.)([A-Z][a-z]+)')
14 | ALL_CAP_RE = re.compile('([a-z0-9])([A-Z])')
15 |
16 |
17 | __all__ = ('merge', 'camel_to_dash', 'default_id', 'not_none', 'not_none_sorted', 'unpack')
18 |
19 |
20 | def merge(first, second):
21 | '''
22 | Recursively merges two dictionnaries.
23 |
24 | Second dictionnary values will take precedance over those from the first one.
25 | Nested dictionnaries are merged too.
26 |
27 | :param dict first: The first dictionnary
28 | :param dict second: The second dictionnary
29 | :return: the resulting merged dictionnary
30 | :rtype: dict
31 | '''
32 | if not isinstance(second, dict):
33 | return second
34 | result = deepcopy(first)
35 | for key, value in iteritems(second):
36 | if key in result and isinstance(result[key], dict):
37 | result[key] = merge(result[key], value)
38 | else:
39 | result[key] = deepcopy(value)
40 | return result
41 |
42 |
43 | def camel_to_dash(value):
44 | '''
45 | Transform a CamelCase string into a low_dashed one
46 |
47 | :param str value: a CamelCase string to transform
48 | :return: the low_dashed string
49 | :rtype: str
50 | '''
51 | first_cap = FIRST_CAP_RE.sub(r'\1_\2', value)
52 | return ALL_CAP_RE.sub(r'\1_\2', first_cap).lower()
53 |
54 |
55 | def default_id(resource, method):
56 | '''Default operation ID generator'''
57 | return '{0}_{1}'.format(method, camel_to_dash(resource))
58 |
59 |
60 | def not_none(data):
61 | '''
62 | Remove all keys where value is None
63 |
64 | :param dict data: A dictionnary with potentialy some values set to None
65 | :return: The same dictionnary without the keys with values to ``None``
66 | :rtype: dict
67 | '''
68 | return dict((k, v) for k, v in iteritems(data) if v is not None)
69 |
70 |
71 | def not_none_sorted(data):
72 | '''
73 | Remove all keys where value is None
74 |
75 | :param OrderedDict data: A dictionnary with potentialy some values set to None
76 | :return: The same dictionnary without the keys with values to ``None``
77 | :rtype: OrderedDict
78 | '''
79 | return OrderedDict((k, v) for k, v in sorted(iteritems(data)) if v is not None)
80 |
81 |
82 | def unpack(response, default_code=HTTPStatus.OK):
83 | '''
84 | Unpack a Flask standard response.
85 |
86 | Flask response can be:
87 | - a single value
88 | - a 2-tuple ``(value, code)``
89 | - a 3-tuple ``(value, code, headers)``
90 |
91 | .. warning::
92 |
93 | When using this function, you must ensure that the tuple is not the reponse data.
94 | To do so, prefer returning list instead of tuple for listings.
95 |
96 | :param response: A Flask style response
97 | :param int default_code: The HTTP code to use as default if none is provided
98 | :return: a 3-tuple ``(data, code, headers)``
99 | :rtype: tuple
100 | :raise ValueError: if the response does not have one of the expected format
101 | '''
102 | if not isinstance(response, tuple):
103 | # data only
104 | return response, default_code, {}
105 | elif len(response) == 1:
106 | # data only as tuple
107 | return response[0], default_code, {}
108 | elif len(response) == 2:
109 | # data and code
110 | data, code = response
111 | return data, code, {}
112 | elif len(response) == 3:
113 | # data, code and headers
114 | data, code, headers = response
115 | return data, code or default_code, headers
116 | else:
117 | raise ValueError('Too many response values')
118 |
--------------------------------------------------------------------------------
/flask_restplus_patched/__init__.py:
--------------------------------------------------------------------------------
1 | from flask_restplus import *
2 | from .api import Api
3 | from .model import Schema, DefaultHTTPErrorSchema
4 | try:
5 | from .model import ModelSchema
6 | except ImportError:
7 | pass
8 | from .namespace import Namespace
9 | from .parameters import Parameters, PostFormParameters, PatchJSONParameters, JSONParameters
10 | from .swagger import Swagger
11 | from .resource import Resource
12 | from .http_exceptions import abort
13 | from ._http import HTTPStatus
14 |
--------------------------------------------------------------------------------
/flask_restplus_patched/_http.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | This file is backported from Python 3.5 http built-in module.
4 | """
5 |
6 | from enum import IntEnum
7 |
8 |
9 | class HTTPStatus(IntEnum):
10 | """HTTP status codes and reason phrases
11 |
12 | Status codes from the following RFCs are all observed:
13 |
14 | * RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616
15 | * RFC 6585: Additional HTTP Status Codes
16 | * RFC 3229: Delta encoding in HTTP
17 | * RFC 4918: HTTP Extensions for WebDAV, obsoletes 2518
18 | * RFC 5842: Binding Extensions to WebDAV
19 | * RFC 7238: Permanent Redirect
20 | * RFC 2295: Transparent Content Negotiation in HTTP
21 | * RFC 2774: An HTTP Extension Framework
22 | """
23 | def __new__(cls, value, phrase, description=''):
24 | obj = int.__new__(cls, value)
25 | obj._value_ = value
26 |
27 | obj.phrase = phrase
28 | obj.description = description
29 | return obj
30 |
31 | def __str__(self):
32 | return str(self.value)
33 |
34 | # informational
35 | CONTINUE = 100, 'Continue', 'Request received, please continue'
36 | SWITCHING_PROTOCOLS = (101, 'Switching Protocols',
37 | 'Switching to new protocol; obey Upgrade header')
38 | PROCESSING = 102, 'Processing'
39 |
40 | # success
41 | OK = 200, 'OK', 'Request fulfilled, document follows'
42 | CREATED = 201, 'Created', 'Document created, URL follows'
43 | ACCEPTED = (202, 'Accepted',
44 | 'Request accepted, processing continues off-line')
45 | NON_AUTHORITATIVE_INFORMATION = (203,
46 | 'Non-Authoritative Information', 'Request fulfilled from cache')
47 | NO_CONTENT = 204, 'No Content', 'Request fulfilled, nothing follows'
48 | RESET_CONTENT = 205, 'Reset Content', 'Clear input form for further input'
49 | PARTIAL_CONTENT = 206, 'Partial Content', 'Partial content follows'
50 | MULTI_STATUS = 207, 'Multi-Status'
51 | ALREADY_REPORTED = 208, 'Already Reported'
52 | IM_USED = 226, 'IM Used'
53 |
54 | # redirection
55 | MULTIPLE_CHOICES = (300, 'Multiple Choices',
56 | 'Object has several resources -- see URI list')
57 | MOVED_PERMANENTLY = (301, 'Moved Permanently',
58 | 'Object moved permanently -- see URI list')
59 | FOUND = 302, 'Found', 'Object moved temporarily -- see URI list'
60 | SEE_OTHER = 303, 'See Other', 'Object moved -- see Method and URL list'
61 | NOT_MODIFIED = (304, 'Not Modified',
62 | 'Document has not changed since given time')
63 | USE_PROXY = (305, 'Use Proxy',
64 | 'You must use proxy specified in Location to access this resource')
65 | TEMPORARY_REDIRECT = (307, 'Temporary Redirect',
66 | 'Object moved temporarily -- see URI list')
67 | PERMANENT_REDIRECT = (308, 'Permanent Redirect',
68 | 'Object moved temporarily -- see URI list')
69 |
70 | # client error
71 | BAD_REQUEST = (400, 'Bad Request',
72 | 'Bad request syntax or unsupported method')
73 | UNAUTHORIZED = (401, 'Unauthorized',
74 | 'No permission -- see authorization schemes')
75 | PAYMENT_REQUIRED = (402, 'Payment Required',
76 | 'No payment -- see charging schemes')
77 | FORBIDDEN = (403, 'Forbidden',
78 | 'Request forbidden -- authorization will not help')
79 | NOT_FOUND = (404, 'Not Found',
80 | 'Nothing matches the given URI')
81 | METHOD_NOT_ALLOWED = (405, 'Method Not Allowed',
82 | 'Specified method is invalid for this resource')
83 | NOT_ACCEPTABLE = (406, 'Not Acceptable',
84 | 'URI not available in preferred format')
85 | PROXY_AUTHENTICATION_REQUIRED = (407,
86 | 'Proxy Authentication Required',
87 | 'You must authenticate with this proxy before proceeding')
88 | REQUEST_TIMEOUT = (408, 'Request Timeout',
89 | 'Request timed out; try again later')
90 | CONFLICT = 409, 'Conflict', 'Request conflict'
91 | GONE = (410, 'Gone',
92 | 'URI no longer exists and has been permanently removed')
93 | LENGTH_REQUIRED = (411, 'Length Required',
94 | 'Client must specify Content-Length')
95 | PRECONDITION_FAILED = (412, 'Precondition Failed',
96 | 'Precondition in headers is false')
97 | REQUEST_ENTITY_TOO_LARGE = (413, 'Request Entity Too Large',
98 | 'Entity is too large')
99 | REQUEST_URI_TOO_LONG = (414, 'Request-URI Too Long',
100 | 'URI is too long')
101 | UNSUPPORTED_MEDIA_TYPE = (415, 'Unsupported Media Type',
102 | 'Entity body in unsupported format')
103 | REQUESTED_RANGE_NOT_SATISFIABLE = (416,
104 | 'Requested Range Not Satisfiable',
105 | 'Cannot satisfy request range')
106 | EXPECTATION_FAILED = (417, 'Expectation Failed',
107 | 'Expect condition could not be satisfied')
108 | UNPROCESSABLE_ENTITY = 422, 'Unprocessable Entity', 'Unprocessable Entity'
109 | LOCKED = 423, 'Locked'
110 | FAILED_DEPENDENCY = 424, 'Failed Dependency'
111 | UPGRADE_REQUIRED = 426, 'Upgrade Required'
112 | PRECONDITION_REQUIRED = (428, 'Precondition Required',
113 | 'The origin server requires the request to be conditional')
114 | TOO_MANY_REQUESTS = (429, 'Too Many Requests',
115 | 'The user has sent too many requests in '
116 | 'a given amount of time ("rate limiting")')
117 | REQUEST_HEADER_FIELDS_TOO_LARGE = (431,
118 | 'Request Header Fields Too Large',
119 | 'The server is unwilling to process the request because its header '
120 | 'fields are too large')
121 |
122 | # server errors
123 | INTERNAL_SERVER_ERROR = (500, 'Internal Server Error',
124 | 'Server got itself in trouble')
125 | NOT_IMPLEMENTED = (501, 'Not Implemented',
126 | 'Server does not support this operation')
127 | BAD_GATEWAY = (502, 'Bad Gateway',
128 | 'Invalid responses from another server/proxy')
129 | SERVICE_UNAVAILABLE = (503, 'Service Unavailable',
130 | 'The server cannot process the request due to a high load')
131 | GATEWAY_TIMEOUT = (504, 'Gateway Timeout',
132 | 'The gateway server did not receive a timely response')
133 | HTTP_VERSION_NOT_SUPPORTED = (505, 'HTTP Version Not Supported',
134 | 'Cannot fulfill request')
135 | VARIANT_ALSO_NEGOTIATES = 506, 'Variant Also Negotiates'
136 | INSUFFICIENT_STORAGE = 507, 'Insufficient Storage'
137 | LOOP_DETECTED = 508, 'Loop Detected'
138 | NOT_EXTENDED = 510, 'Not Extended'
139 | NETWORK_AUTHENTICATION_REQUIRED = (511,
140 | 'Network Authentication Required',
141 | 'The client needs to authenticate to gain network access')
142 |
--------------------------------------------------------------------------------
/flask_restplus_patched/api.py:
--------------------------------------------------------------------------------
1 | from flask import jsonify,current_app
2 | from flask_restplus import Api as OriginalApi
3 | from flask_restplus._http import HTTPStatus
4 | from werkzeug import cached_property
5 |
6 | from .namespace import Namespace
7 | from .swagger import Swagger
8 |
9 |
10 | class Api(OriginalApi):
11 |
12 | @cached_property
13 | def __schema__(self):
14 | # The only purpose of this method is to pass custom Swagger class
15 | if not current_app.config['SWAGGERUI'] :
16 | return None
17 | return Swagger(self).as_dict()
18 |
19 | def init_app(self, app, **kwargs):
20 | # This solves the issue of late resources registration:
21 | # https://github.com/frol/flask-restplus-server-example/issues/110
22 | # https://github.com/noirbizarre/flask-restplus/pull/483
23 | self.app = app
24 |
25 | super(Api, self).init_app(app, **kwargs)
26 | app.errorhandler(HTTPStatus.UNPROCESSABLE_ENTITY.value)(handle_validation_error)
27 |
28 | def namespace(self, *args, **kwargs):
29 | # The only purpose of this method is to pass a custom Namespace class
30 | _namespace = Namespace(*args, **kwargs)
31 | self.add_namespace(_namespace)
32 | return _namespace
33 |
34 |
35 | # 处理422 输入参数异常 Return validation errors as JSON
36 | def handle_validation_error(err):
37 | #exc = err.data['exc']
38 | exc = err.data
39 | return jsonify({
40 | 'status': HTTPStatus.UNPROCESSABLE_ENTITY.value,
41 | 'message': exc['messages']
42 | }), HTTPStatus.UNPROCESSABLE_ENTITY.value
43 |
44 |
45 |
--------------------------------------------------------------------------------
/flask_restplus_patched/http_exceptions.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | HTTP exceptions collection
4 | --------------------------
5 | """
6 |
7 | from flask_restplus.errors import abort as restplus_abort
8 | from flask_restplus._http import HTTPStatus
9 |
10 |
11 | API_DEFAULT_HTTP_CODE_MESSAGES = {
12 | HTTPStatus.UNAUTHORIZED.value: (
13 | "The server could not verify that you are authorized to access the "
14 | "URL requested. You either supplied the wrong credentials (e.g. a bad "
15 | "password), or your browser doesn't understand how to supply the "
16 | "credentials required."
17 | ),
18 | HTTPStatus.FORBIDDEN.value: (
19 | "You don't have the permission to access the requested resource."
20 | ),
21 | HTTPStatus.UNPROCESSABLE_ENTITY.value: (
22 | "The request was well-formed but was unable to be followed due to semantic errors."
23 | )
24 | }
25 |
26 |
27 | def abort(code, message=None, **kwargs):
28 | """
29 | Custom abort function used to provide extra information in the error
30 | response, namely, ``status`` and ``message`` info.
31 | """
32 | if message is None:
33 | if code in API_DEFAULT_HTTP_CODE_MESSAGES: # pylint: disable=consider-using-get
34 | message = API_DEFAULT_HTTP_CODE_MESSAGES[code]
35 | else:
36 | message = HTTPStatus(code).description # pylint: disable=no-value-for-parameter
37 | restplus_abort(code=code, status=code, message=message, **kwargs)
38 |
--------------------------------------------------------------------------------
/flask_restplus_patched/model.py:
--------------------------------------------------------------------------------
1 | from apispec.ext.marshmallow.swagger import fields2jsonschema, field2property
2 | import flask_marshmallow
3 | from werkzeug import cached_property
4 |
5 | from flask_restplus.model import Model as OriginalModel
6 |
7 |
8 | class SchemaMixin(object):
9 |
10 | def __deepcopy__(self, memo):
11 | # XXX: Flask-RESTplus makes unnecessary data copying, while
12 | # marshmallow.Schema doesn't support deepcopyng.
13 | return self
14 |
15 |
16 | class Schema(SchemaMixin, flask_marshmallow.Schema):
17 | pass
18 |
19 |
20 | if flask_marshmallow.has_sqla:
21 | class ModelSchema(SchemaMixin, flask_marshmallow.sqla.ModelSchema):
22 | pass
23 |
24 |
25 | class DefaultHTTPErrorSchema(Schema):
26 | status = flask_marshmallow.base_fields.Integer()
27 | message = flask_marshmallow.base_fields.String()
28 |
29 | def __init__(self, http_code, **kwargs):
30 | super(DefaultHTTPErrorSchema, self).__init__(**kwargs)
31 | self.fields['status'].default = http_code
32 |
33 |
34 | class Model(OriginalModel):
35 |
36 | def __init__(self, name, model, **kwargs):
37 | # XXX: Wrapping with __schema__ is not a very elegant solution.
38 | super(Model, self).__init__(name, {'__schema__': model}, **kwargs)
39 |
40 | @cached_property
41 | def __schema__(self):
42 | schema = self['__schema__']
43 | if isinstance(schema, flask_marshmallow.Schema):
44 | return fields2jsonschema(schema.fields)
45 | elif isinstance(schema, flask_marshmallow.base_fields.FieldABC):
46 | return field2property(schema)
47 | raise NotImplementedError()
48 |
--------------------------------------------------------------------------------
/flask_restplus_patched/resource.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # pylint: disable=protected-access
3 | import flask
4 | from flask_restplus import Resource as OriginalResource
5 | from flask_restplus._http import HTTPStatus
6 | from werkzeug.exceptions import HTTPException
7 |
8 |
9 | class Resource(OriginalResource):
10 | """
11 | Extended Flast-RESTPlus Resource to add options method
12 | """
13 |
14 | @classmethod
15 | def _apply_decorator_to_methods(cls, decorator):
16 | """
17 | This helper can apply a given decorator to all methods on the current
18 | Resource.
19 |
20 | NOTE: In contrast to ``Resource.method_decorators``, which has a
21 | similar use-case, this method applies decorators directly and override
22 | methods in-place, while the decorators listed in
23 | ``Resource.method_decorators`` are applied on every request which is
24 | quite a waste of resources.
25 | """
26 | for method in cls.methods:
27 | method_name = method.lower()
28 | decorated_method_func = decorator(getattr(cls, method_name))
29 | setattr(cls, method_name, decorated_method_func)
30 |
31 | def options(self, *args, **kwargs):
32 | """
33 | Check which methods are allowed.
34 |
35 | Use this method if you need to know what operations are allowed to be
36 | performed on this endpoint, e.g. to decide wether to display a button
37 | in your UI.
38 |
39 | The list of allowed methods is provided in `Allow` response header.
40 | """
41 | # This is a generic implementation of OPTIONS method for resources.
42 | # This method checks every permissions provided as decorators for other
43 | # methods to provide information about what methods `current_user` can
44 | # use.
45 | method_funcs = [getattr(self, m.lower()) for m in self.methods]
46 | allowed_methods = []
47 | request_oauth_backup = getattr(flask.request, 'oauth', None)
48 | for method_func in method_funcs:
49 | if getattr(method_func, '_access_restriction_decorators', None):
50 | if not hasattr(method_func, '_cached_fake_method_func'):
51 | fake_method_func = lambda *args, **kwargs: True
52 | # `__name__` is used in `login_required` decorator, so it
53 | # is required to fake this also
54 | fake_method_func.__name__ = 'options'
55 |
56 | # Decorate the fake method with the registered access
57 | # restriction decorators
58 | for decorator in method_func._access_restriction_decorators:
59 | fake_method_func = decorator(fake_method_func)
60 |
61 | # Cache the `fake_method_func` to avoid redoing this over
62 | # and over again
63 | method_func.__dict__['_cached_fake_method_func'] = fake_method_func
64 | else:
65 | fake_method_func = method_func._cached_fake_method_func
66 |
67 | flask.request.oauth = None
68 | try:
69 | fake_method_func(self, *args, **kwargs)
70 | except HTTPException:
71 | # This method is not allowed, so skip it
72 | continue
73 |
74 | allowed_methods.append(method_func.__name__.upper())
75 | flask.request.oauth = request_oauth_backup
76 |
77 | return flask.Response(
78 | status=HTTPStatus.NO_CONTENT,
79 | headers={'Allow': ", ".join(allowed_methods)}
80 | )
81 |
--------------------------------------------------------------------------------
/flask_restplus_patched/swagger.py:
--------------------------------------------------------------------------------
1 | from apispec.ext.marshmallow.swagger import schema2parameters
2 | from flask_restplus.swagger import Swagger as OriginalSwagger
3 |
4 |
5 | class Swagger(OriginalSwagger):
6 |
7 | def parameters_for(self, doc):
8 | schema = doc['params']
9 |
10 | if not schema:
11 | return []
12 | if isinstance(schema, list):
13 | return schema
14 | if isinstance(schema, dict) and all(isinstance(field, dict) for field in schema.values()):
15 | return list(schema.values())
16 |
17 | if 'in' in schema.context and 'json' in schema.context['in']:
18 | default_location = 'body'
19 | else:
20 | default_location = 'query'
21 | return schema2parameters(schema, default_in=default_location, required=True)
22 |
--------------------------------------------------------------------------------
/kill_python.sh:
--------------------------------------------------------------------------------
1 | ps aux|grep python |grep -v grep|grep -v supervisord|awk '{print $2}'|xargs kill -9
2 |
--------------------------------------------------------------------------------
/logging_config.py:
--------------------------------------------------------------------------------
1 | """logging_config
2 |
3 | Log Config File
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 | import logging.config
12 | # File size in bytes # 文件大小,单位是字节
13 | LOG_FILE_MAX_BYTES = 100 * 1024 * 1024
14 | # The number of rotations # 轮转数量
15 | LOG_FILE_BACKUP_COUNT = 3
16 | log_config = \
17 | {
18 | "version":1,
19 | "disable_existing_loggers":False,
20 | "formatters":{
21 | "normal_formatter":{
22 | "format":"%(asctime)s %(levelname)s %(process)d %(thread)d [%(pathname)s:%(lineno)s] %(message)s"
23 | },
24 | "sql_formatter": {
25 | "format": "%(asctime)s %(levelname)s [%(process)d %(thread)d] %(message)s"
26 | }
27 | },
28 | "handlers":{
29 | "console":{
30 | "class":"logging.StreamHandler",
31 | "level":"DEBUG",
32 | "formatter":"normal_formatter",
33 | "stream":"ext://sys.stdout"
34 | },
35 | "debug_file_handler":{
36 | "class":"logging.handlers.RotatingFileHandler",
37 | "level":"DEBUG",
38 | "formatter":"normal_formatter",
39 | "filename":"log/debug.log",
40 | "maxBytes":LOG_FILE_MAX_BYTES,
41 | "backupCount":LOG_FILE_BACKUP_COUNT,
42 | "encoding":"utf8"
43 | },
44 | "info_file_handler":{
45 | "class":"logging.handlers.RotatingFileHandler",
46 | "level":"INFO",
47 | "formatter":"normal_formatter",
48 | "filename":"log/info.log",
49 | "maxBytes":LOG_FILE_MAX_BYTES,
50 | "backupCount":LOG_FILE_BACKUP_COUNT,
51 | "encoding":"utf8"
52 | },
53 | "dao_file_handler":{
54 | "class":"logging.handlers.RotatingFileHandler",
55 | "level":"DEBUG",
56 | "formatter":"normal_formatter",
57 | "filename":"log/dao.log",
58 | "maxBytes":LOG_FILE_MAX_BYTES,
59 | "backupCount":LOG_FILE_BACKUP_COUNT,
60 | "encoding":"utf8"
61 | },
62 | "sql_file_handler":{
63 | "class":"logging.handlers.RotatingFileHandler",
64 | "level":"DEBUG",
65 | "formatter":"sql_formatter",
66 | "filename":"log/sql.log",
67 | "maxBytes":LOG_FILE_MAX_BYTES,
68 | "backupCount":LOG_FILE_BACKUP_COUNT,
69 | "encoding":"utf8"
70 | },
71 | "error_file_handler":{
72 | "class":"logging.handlers.RotatingFileHandler",
73 | "level":"ERROR",
74 | "formatter":"normal_formatter",
75 | "filename":"log/errors.log",
76 | "maxBytes":LOG_FILE_MAX_BYTES,
77 | "backupCount":LOG_FILE_BACKUP_COUNT,
78 | "encoding":"utf8"
79 | },
80 | "flask_file_handler":{
81 | "class":"logging.handlers.RotatingFileHandler",
82 | "level":"DEBUG",
83 | "formatter":"normal_formatter",
84 | "filename":"log/flask.log",
85 | "maxBytes":LOG_FILE_MAX_BYTES,
86 | "backupCount":LOG_FILE_BACKUP_COUNT,
87 | "encoding":"utf8"
88 | },
89 | "stock_update_file_handler":{
90 | "class":"logging.handlers.RotatingFileHandler",
91 | "level":"INFO",
92 | "formatter":"normal_formatter",
93 | "filename":"log/stock_update.log",
94 | "maxBytes":LOG_FILE_MAX_BYTES,
95 | "backupCount":LOG_FILE_BACKUP_COUNT,
96 | "encoding":"utf8"
97 | }
98 | },
99 | "loggers":{
100 | "dao":{
101 | "level":"DEBUG",
102 | "handlers":["dao_file_handler"],
103 | "propagate":"no"
104 | },
105 | "sqlalchemy.engine":{
106 | "level":"DEBUG",
107 | "handlers":["sql_file_handler"],
108 | "propagate":"no"
109 | },
110 | "flask.app":{
111 | "level":"DEBUG",
112 | "handlers":["flask_file_handler"],
113 | "propagate":"no"
114 | },
115 | "stock_update":{
116 | "level":"DEBUG",
117 | "handlers":["stock_update_file_handler"],
118 | "propagate":"no"
119 | }
120 | },
121 | "root":{
122 | "level":"INFO",
123 | "handlers":["console","debug_file_handler","error_file_handler"]
124 | }
125 | }
126 |
127 | logging.config.dictConfig(log_config)
128 | # Usage # 使用方法
129 | # daoLogger = logging.getLogger("dao")
130 | # daoLogger.info('dao')
131 | # daoLoggerSub1 = logging.getLogger("dao.sub1")
132 | # daoLoggerSub1.error('daoSub1')
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | """manage
2 |
3 | BaoAI Backend Main File
4 |
5 | PROJECT: BaoAI Backend
6 | VERSION: 2.0.0
7 | AUTHOR: henry <703264459@qq.com>
8 | WEBSITE: http://www.baoai.co
9 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
10 | LICENSE: Apache-2.0
11 | """
12 | import os
13 | from flask_migrate import Migrate, MigrateCommand
14 | from flask_script import Manager, Shell, Server, Command
15 | from flask_script.commands import Clean, ShowUrls
16 | from app import create_app, db
17 |
18 | # app,celery = create_app()
19 | app = create_app()
20 | manager = Manager(app)
21 | migrate = Migrate(app, db)
22 |
23 | def make_shell_context():
24 | from app.modules.admin.model import Admin
25 | return dict(app=app, db=db, Admin=Admin)
26 |
27 | # Get BaoAI version and URL # 获取BaoAI版本及官方URL
28 | @manager.command
29 | def baoai():
30 | print('BaoAI v2.0.0 - http://www.baoai.co')
31 |
32 | manager.add_command("runserver", Server(host='0.0.0.0', port=5000))
33 | manager.add_command("shell", Shell(make_context=make_shell_context))
34 | manager.add_command("db", MigrateCommand) # Database Manage # 数据库管理
35 | manager.add_command("clean", Clean()) # Clean Cache File # 清理缓存文件
36 | manager.add_command("url", ShowUrls()) # Print All URL # 打印所有URL
37 |
38 | if __name__ == "__main__":
39 | manager.run()
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/remote_debug.py:
--------------------------------------------------------------------------------
1 | """remote_debug
2 |
3 | Remote Debug Main File For Visual Studio Code
4 | 仅用于Visual Studio Code的远程调试入口文件
5 |
6 | PROJECT: BaoAI Backend
7 | AUTHOR: henry <703264459@qq.com>
8 | WEBSITE: http://www.baoai.co
9 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
10 | LICENSE: Apache-2.0
11 | """
12 | import os
13 | from app import create_app, db
14 |
15 | if __name__ == '__main__':
16 | app = create_app(os.getenv('FLASK_CONFIG') or 'default')
17 | app.debug = False
18 | app.run(host='localhost', port=5002)
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | absl-py==0.7.1
2 | aiodns==1.1.1
3 | aiohttp==3.6.1
4 | alabaster==0.7.12
5 | alembic==0.8.10
6 | amqp==2.5.1
7 | aniso8601==4.1.0
8 | apispec==0.38.0
9 | arrow==0.15.2
10 | asn1crypto==0.24.0
11 | astor==0.8.0
12 | async-timeout==3.0.1
13 | attrs==18.2.0
14 | Babel==2.7.0
15 | backcall==0.1.0
16 | backtrader==1.9.74.123
17 | backtrader-plotting==0.5.3
18 | bcrypt==3.1.6
19 | beautifulsoup4==4.8.0
20 | billiard==3.6.1.0
21 | bleach==1.5.0
22 | bokeh==1.0.4
23 | bs4==0.0.1
24 | ccxt==1.18.1225
25 | celery==4.3.0
26 | certifi==2019.3.9
27 | cffi==1.12.2
28 | chardet==3.0.4
29 | Click==7.0
30 | colorama==0.4.1
31 | colorlog==4.0.2
32 | cryptography==2.6.1
33 | cycler==0.10.0
34 | dash==1.4.0
35 | dash-core-components==1.3.0
36 | dash-html-components==1.0.1
37 | dash-renderer==1.1.1
38 | dash-table==4.4.0
39 | decorator==4.4.0
40 | defusedxml==0.6.0
41 | dnspython==1.16.0
42 | docutils==0.14
43 | empyrical==0.5.3
44 | entrypoints==0.3
45 | eventlet==0.25.1
46 | fabric==2.4.0
47 | Fabric3==1.13.1.post1
48 | Flask==1.0.2
49 | Flask-Compress==1.4.0
50 | Flask-Cors==3.0.2
51 | Flask-Login==0.4.0
52 | flask-marshmallow==0.7.0
53 | Flask-Migrate==2.4.0
54 | flask-restplus==0.11.0
55 | flask-restplus-marshmallow==0.2.20
56 | Flask-Script==2.0.6
57 | flask-sqlacodegen==1.1.6.1
58 | Flask-SQLAlchemy==2.2
59 | flower==0.9.3
60 | future==0.18.0
61 | gast==0.2.2
62 | greenlet==0.4.15
63 | grpcio==1.23.0
64 | gunicorn==20.0.4
65 | h5py==2.9.0
66 | html5lib==0.9999999
67 | IbPy2==0.8.0
68 | idna==2.8
69 | idna-ssl==1.1.0
70 | imagesize==1.1.0
71 | importlib-metadata==0.23
72 | inflect==2.1.0
73 | invoke==1.2.0
74 | ipykernel==5.1.2
75 | ipython==7.7.0
76 | ipython-genutils==0.2.0
77 | ipywidgets==7.5.1
78 | itsdangerous==1.1.0
79 | jedi==0.15.1
80 | Jinja2==2.10
81 | joblib==0.13.2
82 | jsonpickle==1.2
83 | jsonschema==3.0.0
84 | jupyter==1.0.0
85 | jupyter-client==5.3.1
86 | jupyter-console==6.0.0
87 | jupyter-core==4.5.0
88 | Keras==2.1.6
89 | kiwisolver==1.1.0
90 | kombu==4.6.4
91 | lockfile==0.12.2
92 | lxml==4.4.1
93 | Mako==1.0.7
94 | Markdown==3.1.1
95 | MarkupSafe==1.1.1
96 | marshmallow==2.18.1
97 | marshmallow-sqlalchemy==0.12.0
98 | matplotlib==3.1.1
99 | mistune==0.8.4
100 | monotonic==1.5
101 | more-itertools==7.2.0
102 | mpld3==0.3
103 | multidict==4.5.2
104 | multitasking==0.0.9
105 | nbconvert==5.6.0
106 | nbformat==4.4.0
107 | notebook==6.0.1
108 | numexpr==2.7.0
109 | numpy==1.17.0
110 | oandapy==0.0.9
111 | opencv-python==4.1.0.25
112 | packaging==19.0
113 | pandas==0.25.1
114 | pandas-datareader==0.7.4
115 | pandocfilters==1.4.2
116 | paramiko==2.4.2
117 | parso==0.5.1
118 | passlib==1.7.1
119 | pdir2==0.3.1.post2
120 | permission==0.4.1
121 | pexpect==4.7.0
122 | pickleshare==0.7.5
123 | Pillow==6.1.0
124 | plotly==4.1.1
125 | pony==0.7.9
126 | prometheus-client==0.7.1
127 | prompt-toolkit==2.0.9
128 | protobuf==3.9.1
129 | psutil==5.6.3
130 | ptyprocess==0.6.0
131 | py-cpuinfo==5.0.0
132 | pyasn1==0.4.5
133 | pycares==3.0.0
134 | pycparser==2.19
135 | pyfolio==0.9.2
136 | Pygments==2.4.2
137 | PyMySQL==0.9.3
138 | PyNaCl==1.3.0
139 | pyparsing==2.4.0
140 | pyrsistent==0.14.11
141 | pysimplemodel==2.3.3
142 | pytdx==1.72
143 | python-dateutil==2.8.0
144 | python-editor==1.0.4
145 | python-status==1.0.1
146 | pytz==2018.9
147 | pywinpty==0.5.5
148 | PyYAML==3.13
149 | pyzmq==18.1.0
150 | qtconsole==4.5.4
151 | redis==3.3.8
152 | requests==2.21.0
153 | retrying==1.3.3
154 | scikit-learn==0.21.3
155 | scipy==1.3.1
156 | seaborn==0.9.0
157 | Send2Trash==1.5.0
158 | simplejson==3.16.0
159 | six==1.12.0
160 | sklearn==0.0
161 | snowballstemmer==1.2.1
162 | soupsieve==1.9.3
163 | Sphinx==2.1.0
164 | sphinx-bootstrap-theme==0.7.1
165 | sphinx-rtd-theme==0.4.3
166 | sphinxcontrib-applehelp==1.0.1
167 | sphinxcontrib-devhelp==1.0.1
168 | sphinxcontrib-htmlhelp==1.0.2
169 | sphinxcontrib-jsmath==1.0.1
170 | sphinxcontrib-qthelp==1.0.2
171 | sphinxcontrib-serializinghtml==1.1.3
172 | sqlacodegen==2.0.1
173 | SQLAlchemy==1.1.5
174 | SQLAlchemy-Utils==0.32.12
175 | sqlautocode==0.7
176 | supervisor==4.1.0
177 | tensorboard==1.8.0
178 | tensorflow==1.8.0
179 | termcolor==1.1.0
180 | terminado==0.8.2
181 | testpath==0.4.2
182 | tornado==5.1.1
183 | traitlets==4.3.2
184 | tushare==1.2.48
185 | typing-extensions==3.7.4
186 | urllib3==1.24.1
187 | var-dump==1.2
188 | vine==1.3.0
189 | wcwidth==0.1.7
190 | webargs==5.1.2
191 | Werkzeug==0.14.1
192 | widgetsnbextension==3.5.1
193 | wincertstore==0.2
194 | wrapt==1.11.2
195 | yarl==1.1.0
196 | yfinance==0.1.45
197 | zipp==0.6.0
198 |
--------------------------------------------------------------------------------
/requirements_talib.txt:
--------------------------------------------------------------------------------
1 | TA-Lib==0.4.17
--------------------------------------------------------------------------------
/run_baoai.bat:
--------------------------------------------------------------------------------
1 | venv\Scripts\python manage.py runserver --threaded
--------------------------------------------------------------------------------
/run_baoai.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | basepath=$(cd `dirname $0`; pwd)
3 | cd ${basepath}
4 | venv/bin/gunicorn manage:app -c deploy/gunicorn_config.py
5 |
6 |
--------------------------------------------------------------------------------
/run_www.bat:
--------------------------------------------------------------------------------
1 | venv\Scripts\python www_manage.py runserver --threaded
--------------------------------------------------------------------------------
/run_www.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | basepath=$(cd `dirname $0`; pwd)
3 | cd ${basepath}
4 | venv/bin/gunicorn www_manage:app -c deploy/gunicorn_config.py
5 |
6 |
--------------------------------------------------------------------------------
/static/ai/iris/3c099ad2-4ed1-11ea-a3e0-b42e9995d7c8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/static/ai/iris/3c099ad2-4ed1-11ea-a3e0-b42e9995d7c8.png
--------------------------------------------------------------------------------
/static/ai/iris/c988de40-5330-11ea-aa9b-b42e9995d7c8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/static/ai/iris/c988de40-5330-11ea-aa9b-b42e9995d7c8.png
--------------------------------------------------------------------------------
/static/uploads/2020/01/02/e4a77d02199947d4b0066aa9bd4e8b57.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/static/uploads/2020/01/02/e4a77d02199947d4b0066aa9bd4e8b57.jpg
--------------------------------------------------------------------------------
/static/uploads/2020/01/03/eff0930192824964b3dbc0a716c8c5a9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/static/uploads/2020/01/03/eff0930192824964b3dbc0a716c8c5a9.png
--------------------------------------------------------------------------------
/static/uploads/2020/02/14/4fcc3b62d0f94421b56226a691eeb2fd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuanbaonet/baoaiback/0fb1b604185a8bd8b72c1d2d527fb94bbaf46a86/static/uploads/2020/02/14/4fcc3b62d0f94421b56226a691eeb2fd.png
--------------------------------------------------------------------------------
/www/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 | from flask import Flask, Blueprint
3 | from flask_sqlalchemy import SQLAlchemy
4 | from flask_cors import CORS
5 | from config import config
6 | from celery import Celery
7 | import arrow
8 | import logging_config
9 |
10 | db = SQLAlchemy()
11 | Config = config[os.getenv('FLASK_CONFIG') or 'default']
12 | celery = None
13 |
14 | def create_app():
15 | app = Flask(__name__, static_url_path=Config.APP_STATIC_URL_PATH, static_folder=Config.STATIC_FOLDER, template_folder=Config.SITE_TEMPLATE_FOLDER)
16 | app.config.from_object(Config)
17 | db.init_app(app)
18 | db.app = app
19 | # 解决禁止跨域请求的问题
20 | if app.config['CORS_ENABLED']:
21 | CORS(app, supports_credentials=True)
22 |
23 | # init Celery
24 | # global celery
25 | # celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'], backend=app.config['CELERY_RESULT_BACKEND'])
26 | # celery.conf.update(app.config)
27 |
28 | from . import modules
29 | modules.init_app(app)
30 |
31 | @app.template_global('now')
32 | def now_datetime(format='YYYY-MM-DD HH:mm:ss'):
33 | return arrow.now().format(format)
34 | return app #, celery
35 |
--------------------------------------------------------------------------------
/www/modules/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 | from flask import current_app
3 | import traceback
4 |
5 | def file_name(file_dir):
6 | modules_dirs = []
7 | for root, dirs, files in os.walk(file_dir):
8 | dirs.remove('__pycache__')
9 | modules_dirs = dirs
10 | break
11 | # print('root_dir:', root) # 当前目录路径
12 | # print('sub_dirs:', dirs) # 当前路径下所有子目录
13 | # print('files:', files) # 当前路径下所有非目录子文件
14 | return modules_dirs
15 |
16 |
17 | def init_app(app, **kwargs):
18 | basedir = os.path.abspath(os.path.dirname(__file__))
19 | modules_dirs = file_name(basedir)
20 | from importlib import import_module
21 | # for module_name in app.config['ENABLED_MODULES']:
22 | for module_name in modules_dirs:
23 | # import_module('.%s' % module_name, package=__name__).init_app(app, **kwargs)
24 | try:
25 | import_module('.%s' % module_name, package=__name__).init_app(app, **kwargs)
26 | except Exception as e:
27 | print('%s module exception, traceback:\n%s' % (module_name, traceback.format_exc()))
--------------------------------------------------------------------------------
/www/modules/about/__init__.py:
--------------------------------------------------------------------------------
1 | """configs
2 |
3 | Init main module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 | from flask import Blueprint
12 | about = Blueprint('about', __name__)
13 | def init_app(app, **kwargs):
14 | """
15 | Init Article module.
16 | """
17 | from . import views # , task
18 | app.register_blueprint(about)
19 |
--------------------------------------------------------------------------------
/www/modules/about/task.py:
--------------------------------------------------------------------------------
1 | """configs
2 |
3 | Init task module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 | from www import celery
12 | from celery.schedules import crontab
13 |
14 | @celery.task
15 | def test1(arg1, arg2):
16 | result = arg1 + arg2
17 | return result
18 |
19 | @celery.task
20 | def test2(arg):
21 | print(arg)
22 |
23 | @celery.on_after_configure.connect
24 | def setup_periodic_tasks(sender, **kwargs):
25 | sender.add_periodic_task(
26 | crontab(hour=7, minute=30, day_of_week=1),
27 | test2.s('Happy Mondays!'),
28 | )
29 |
30 |
--------------------------------------------------------------------------------
/www/modules/about/views.py:
--------------------------------------------------------------------------------
1 | """configs
2 |
3 | Init views module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 | from flask import render_template,url_for,redirect,flash,current_app,\
12 | request,abort, make_response
13 | from . import about
14 |
15 | @about.route('/about', methods=['GET','POST'])
16 | def index():
17 | baoai = {}
18 | baoai['title'] = 'BaoAI'
19 | return render_template('about/index.html',baoai=baoai)
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/www/modules/main/__init__.py:
--------------------------------------------------------------------------------
1 | """configs
2 |
3 | Init main module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 | from flask import Blueprint
12 | main = Blueprint('main', __name__)
13 | def init_app(app, **kwargs):
14 | """
15 | Init Article module.
16 | """
17 | from . import views # , task
18 | app.register_blueprint(main)
19 |
--------------------------------------------------------------------------------
/www/modules/main/task.py:
--------------------------------------------------------------------------------
1 | """configs
2 |
3 | Init task module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 | from www import celery
12 | from celery.schedules import crontab
13 |
14 | @celery.task
15 | def test1(arg1, arg2):
16 | result = arg1 + arg2
17 | return result
18 |
19 | @celery.task
20 | def test2(arg):
21 | print(arg)
22 |
23 | @celery.on_after_configure.connect
24 | def setup_periodic_tasks(sender, **kwargs):
25 | sender.add_periodic_task(
26 | crontab(hour=7, minute=30, day_of_week=1),
27 | test2.s('Happy Mondays!'),
28 | )
29 |
30 |
--------------------------------------------------------------------------------
/www/modules/main/views.py:
--------------------------------------------------------------------------------
1 | """configs
2 |
3 | Init views module
4 |
5 | PROJECT: BaoAI Backend
6 | AUTHOR: henry <703264459@qq.com>
7 | WEBSITE: http://www.baoai.co
8 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
9 | LICENSE: Apache-2.0
10 | """
11 | from flask import render_template,url_for,redirect,flash,current_app,\
12 | request,abort, make_response
13 | from . import main
14 | from flask_sqlalchemy import get_debug_queries
15 |
16 | @main.after_app_request
17 | def after_request(response):
18 | for query in get_debug_queries():
19 | if query.duration >= current_app.config['FLASKY_SLOW_DB_QUERY_TIME']:
20 | current_app.logger.warning(
21 | 'Slow query: %s\nParameters:%s\nDuration:%fs\nContext: %s\n'
22 | %(query.statement, query.parameters, query.duration, query.context))
23 | return response
24 |
25 | @main.route('/', methods=['GET','POST'])
26 | def index():
27 | baoai = {}
28 | baoai['title'] = 'BaoAI'
29 | return render_template('main/index.html',baoai=baoai)
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/www/templates/about/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{baoai.title}}
8 |
9 |
10 |
11 | BaoAI : {{now('YYYY-MM-DD')}}
12 |
13 |
14 |
--------------------------------------------------------------------------------
/www/templates/main/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{baoai.title}}
8 |
9 |
10 |
11 | BaoAI : {{now('YYYY-MM-DD')}}
12 |
13 |
14 |
--------------------------------------------------------------------------------
/www_manage.py:
--------------------------------------------------------------------------------
1 | """manage
2 |
3 | BaoAI Backend WWW Main File
4 |
5 | PROJECT: BaoAI Backend
6 | VERSION: 1.0.0
7 | AUTHOR: henry <703264459@qq.com>
8 | WEBSITE: http://www.baoai.co
9 | COPYRIGHT: Copyright © 2016-2020 广州源宝网络有限公司 Guangzhou Yuanbao Network Co., Ltd. ( http://www.ybao.org )
10 | LICENSE: Apache-2.0
11 | """
12 | import os
13 | from flask_migrate import Migrate, MigrateCommand
14 | from flask_script import Manager, Shell, Server
15 | from flask_script.commands import Clean, ShowUrls
16 | from www import create_app, db
17 |
18 | app = create_app()
19 | manager = Manager(app)
20 | migrate = Migrate(app, db)
21 |
22 | # Get BaoAI version and URL # 获取BaoAI版本及官方URL
23 | @manager.command
24 | def baoai():
25 | print('BaoAI v2.0.0 - http://www.baoai.co')
26 |
27 | manager.add_command("runserver", Server(host="0.0.0.0", port=5005))
28 | manager.add_command("db", MigrateCommand) # Database Manage # 数据库管理
29 | manager.add_command("clean", Clean()) # Clean Cache File # 清理缓存文件
30 | manager.add_command("url", ShowUrls()) # Print All URL # 打印所有URL
31 |
32 | if __name__ == '__main__':
33 | manager.run()
34 |
--------------------------------------------------------------------------------