Skip to content

Commit ab9502b

Browse files
authored
Merge pull request #56 from TaleLin/dev
Feat/file upload (#55)
2 parents 0a631e6 + 24026a0 commit ab9502b

File tree

12 files changed

+105
-10
lines changed

12 files changed

+105
-10
lines changed

Pipfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Flask = "==1.0.2"
1212
Flask-SQLAlchemy = "==2.3.2"
1313
Flask-WTF = "==0.14.2"
1414
Flask-Cors = "==2.1.0"
15-
Lin-CMS = "==0.1.1b1"
15+
Lin-CMS = "==0.1.1b3"
1616

1717
[dev-packages]
1818
pytest = "*"

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ Lin-CMS 是林间有风团队经过大量项目实践所提炼出的一套**内
3535

3636
## 最新版本
3737

38-
核心库:0.1.1b1
38+
核心库:0.1.1b3
3939

40-
示例工程:0.1.0-beta.1
40+
示例工程:0.1.0-beta.2
4141

4242

4343
### 文档地址
@@ -177,4 +177,4 @@ pipenv shell
177177

178178
## 下个版本开发计划
179179

180-
- [ ] 调整 jwt 机制,增强灵活性
180+
- [ ] 系统访问日志、错误日志

app/api/cms/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ def create_cms():
1313
from .admin import admin_api
1414
from .user import user_api
1515
from .log import log_api
16+
from .file import file_api
1617
from .test import test_api
1718
admin_api.register(cms)
1819
user_api.register(cms)
1920
log_api.register(cms)
21+
file_api.register(cms)
2022
test_api.register(cms)
2123
return cms

app/api/cms/file.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""
2+
:copyright: © 2019 by the Lin team.
3+
:license: MIT, see LICENSE for more details.
4+
"""
5+
from flask import request, jsonify
6+
from lin import login_required
7+
from lin.redprint import Redprint
8+
9+
from app.extensions.file.local_uploader import LocalUploader
10+
11+
file_api = Redprint('file')
12+
13+
14+
@file_api.route('/', methods=['POST'])
15+
@login_required
16+
def post_file():
17+
files = request.files
18+
uploader = LocalUploader(files)
19+
ret = uploader.upload()
20+
return jsonify(ret)

app/api/cms/user.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
from lin.redprint import Redprint
1818

1919
from app.libs.error_code import RefreshException
20-
from app.validators.forms import LoginForm, RegisterForm, ChangePasswordForm, UpdateInfoForm
20+
from app.validators.forms import LoginForm, RegisterForm, ChangePasswordForm, UpdateInfoForm, \
21+
AvatarUpdateForm
2122

2223
user_api = Redprint('user')
2324

@@ -136,6 +137,16 @@ def get_allowed_apis():
136137
return jsonify(user)
137138

138139

140+
@user_api.route('/avatar', methods=['PUT'])
141+
@login_required
142+
def set_avatar():
143+
form = AvatarUpdateForm().validate_for_api()
144+
user = get_current_user()
145+
with db.auto_commit():
146+
user.avatar = form.avatar.data
147+
return Success(msg='更新头像成功')
148+
149+
139150
def _register_user(form: RegisterForm):
140151
with db.auto_commit():
141152
# 注意:此处使用挂载到manager上的user_model,不可使用默认的User

app/app.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def create_tables(app):
2626

2727

2828
def create_app(register_all=True):
29-
app = Flask(__name__)
29+
app = Flask(__name__, static_folder='./assets')
3030
app.config.from_object('app.config.setting')
3131
app.config.from_object('app.config.secure')
3232
if register_all:

app/extensions/file/config.py

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# 文件相关配置
2+
FILE = {
3+
"STORE_DIR": 'app/assets',
4+
"SINGLE_LIMIT": 1024 * 1024 * 2,
5+
"TOTAL_LIMIT": 1024 * 1024 * 20,
6+
"NUMS": 10,
7+
"INCLUDE": set([]),
8+
"EXCLUDE": set([])
9+
}

app/extensions/file/local_uploader.py

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from flask import current_app
2+
from werkzeug.utils import secure_filename
3+
4+
from lin.core import File
5+
from lin.file import Uploader
6+
7+
8+
class LocalUploader(Uploader):
9+
10+
def upload(self):
11+
ret = []
12+
site_domain = current_app.config.get('SITE_DOMAIN')\
13+
if current_app.config.get('SITE_DOMAIN') else 'http://127.0.0.1:5000'
14+
for single in self._file_storage:
15+
file_md5 = self._generate_md5(single.read())
16+
single.seek(0)
17+
exists = File.query.filter_by(md5=file_md5).first()
18+
if exists:
19+
ret.append({
20+
"key": single.name,
21+
"id": exists.id,
22+
"url": site_domain + '/assets/' + exists.path
23+
})
24+
else:
25+
absolute_path, relative_path, real_name = self._get_store_path(single.filename)
26+
secure_filename(single.filename)
27+
single.save(absolute_path)
28+
file = File.create_file(
29+
name=real_name,
30+
path=relative_path,
31+
extension=self._get_ext(single.filename),
32+
size=self._get_size(single),
33+
md5=file_md5,
34+
commit=True
35+
)
36+
ret.append({
37+
"key": single.name,
38+
"id": file.id,
39+
"url": site_domain + '/assets/' + file.path
40+
})
41+
return ret

app/validators/forms.py

+6
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ class UpdateUserInfoForm(Form):
141141
])
142142

143143

144+
class AvatarUpdateForm(Form):
145+
avatar = StringField('头像', validators=[
146+
DataRequired(message='请输入头像url')
147+
])
148+
149+
144150
class BookSearchForm(Form):
145151
q = StringField(validators=[DataRequired(message='必须传入搜索关键字')]) # 前端的请求参数中必须携带`q`
146152

code.md

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626

2727
10100 refresh token 获取失败
2828

29+
10110 文件体积过大
30+
31+
10120 文件数量过多
32+
33+
10130 文件扩展名不符合规范
34+
2935
20000 werkzeug 中的HTTP EXCEPTION,error_code统一为1007,前端应读取msg
3036

3137
## 项目使用的状态码

plugin_init.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,12 @@ def __update_setting(self, new_setting):
144144
sub_str = 'PLUGIN_PATH = ' + self.__format_setting(final_setting)
145145

146146
setting_path = self.app.config.root_path + '/config/setting.py'
147-
with open(setting_path, 'r') as f:
147+
with open(setting_path, 'r', encoding='UTF-8') as f:
148148
content = f.read()
149149
pattern = 'PLUGIN_PATH = \{([\s\S]*)\}+.*?'
150150
result = re.sub(pattern, sub_str, content)
151151

152-
with open(setting_path, 'w+') as f:
152+
with open(setting_path, 'w+', encoding='UTF-8') as f:
153153
f.write(result)
154154

155155
def __get_all_plugins(self):
@@ -255,7 +255,7 @@ def __generate_plugin_graph(self):
255255
'.', '/').replace('app', '')
256256
requirements_path = self.app.config.root_path + \
257257
plugin_path + '/requirements.txt'
258-
with open(requirements_path, 'r') as f:
258+
with open(requirements_path, 'r', encoding='UTF-8') as f:
259259
while True:
260260

261261
# 正则匹配requirements的每一行的信息

requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Flask-WTF==0.14.2
1010
idna==2.6
1111
itsdangerous==1.1.0
1212
Jinja2==2.10
13-
Lin-CMS==0.1.1b1
13+
Lin-CMS==0.1.1b3
1414
MarkupSafe==1.1.1
1515
pipfile==0.0.2
1616
PyJWT==1.7.1

0 commit comments

Comments
 (0)