Commit 796e9b1b authored by wanli's avatar wanli

feat(): 打通应用添加前后端

parent be326b71
......@@ -60,14 +60,7 @@ def _custom_abort(http_status_code, **kwargs):
自定义abort 400响应数据格式
"""
if http_status_code == 400:
message = kwargs.get('msg')
if isinstance(message, dict):
param, info = list(message.items())[0]
data = '{}:{}!'.format(param, info)
return abort(jsonify(response_result(ResponseCode.HTTP_INVAILD_REQUEST, data=data)))
else:
return abort(jsonify(response_result(ResponseCode.HTTP_INVAILD_REQUEST, data=message)))
# return { 'code': http_status_code, 'msg': kwargs.get('message') }
return abort(jsonify(response_result(ResponseCode.HTTP_INVAILD_REQUEST, data=kwargs)))
return abort(http_status_code)
def _access_control(response):
......
......@@ -5,6 +5,7 @@ import os
import re
import json
import shutil
from pathlib import Path
from datetime import datetime
from sqlalchemy import func, distinct
from application.app import db
......@@ -157,7 +158,9 @@ class AppResource(object):
# result = Apps.select(app_name=data.get("app_name"), is_delete=False).count()
# if result < 1:
# return False, "app_name has been exists."
algorithm = params.get('algorithm')
if algorithm:
params.pop("algorithm")
params.update({
'app_icon': params["app_icon"].replace(config.UPLOAD_ROOT_DIR, ""),
'create_by': user.id,
......@@ -167,39 +170,47 @@ class AppResource(object):
})
app_files = []
epk_path = ""
epk_path = Path("")
if params.get("fileList"):
app_files = params.get("fileList")
params.pop("fileList")
epk_path = params.get("epk_path")
params.pop("epk_path")
if params.get("logo"):
params.pop("logo")
app = AppModel(**params)
db.session.add(app)
db.session.commit()
# 在EPK目录下生成JSON文件
with open(os.sep.join([os.path.dirname(epk_path), "epk.json"]), "w") as f:
json.dump(app.to_dict(), f)
epk_path.joinpath("epk.json").write_text(json.dumps(app.to_dict()), encoding="utf-8")
# with open(os.sep.join([os.path.dirname(epk_path), "epk.json"]), "w") as f:
# json.dump(app.to_dict(), f)
logger.info(app_files)
for a in app_files:
res = AnnexModel(app=app, title=os.path.basename(a), path=a, size=os.path.getsize(a), create_by=user, create_at=datetime.now(), update_by=user, update_at=datetime.now())
res = AnnexModel(app=app.id, title=os.path.basename(a), path=a, size=os.path.getsize(a), create_by=user.id, create_at=datetime.now(), update_by=user.id, update_at=datetime.now())
db.session.add(res)
db.session.flush()
db.session.commit()
app_info = {}
params = { 'appName': app.app_name, 'appDir': epk_path, 'appVersion': app.app_version, 'output': os.path.dirname(epk_path) }
params = { 'appName': app.app_name, 'appDir': epk_path.resolve().as_posix(), 'appVersion': app.app_version, 'output': epk_path.parent.resolve().as_posix() }
if user.role == "administrator" or user.role == "community":
params['algorithm'] ="h"
if algorithm:
params['algorithm'] = algorithm
epk = EpkApp(**params)
app_info = epk.pack()
epk_filename = os.sep.join([os.path.dirname(epk_path).replace(config.UPLOAD_ROOT_DIR, ""), "{}.epk".format(app.app_name)]).replace('\\', '/')
epk_filename = epk_path.relative_to(config.UPLOAD_ROOT_DIR).joinpath("{}.epk".format(app.app_name)).resolve().as_posix()
if app_info:
app_info['md5'] = str(app_info['md5'])
package = PackageModel(app=app, file_path=epk_filename, app_version=params.get("app_version"), package_info=app_info, source=1, create_by=user, create_at=datetime.now(), update_by=user, update_at=datetime.now())
package = PackageModel(app=app.id, file_path=epk_filename, app_version=params.get("appVersion"), package_info=json.dumps(app_info), source=1, create_by=user.id, create_at=datetime.now(), update_by=user.id, update_at=datetime.now(), remarks=json.dumps(params))
db.session.add(package)
db.session.commit()
......
......@@ -10,20 +10,20 @@ class AppModel(PrimaryModel):
app_name = db.Column(db.String(70), index = True, nullable = False)
app_icon = db.Column(db.String(200), nullable = False)
app_version = db.Column(db.String(20), nullable = False)
category = db.Column(db.Integer, nullable = False)
category_2th = db.Column(db.Integer, nullable = False)
developer = db.Column(db.Integer, nullable = False)
download_url = db.Column(db.String(20), nullable = False, default = '')
category = db.Column(db.String(50), nullable = False)
category_2th = db.Column(db.String(50), nullable = False)
developer = db.Column(db.String(50), nullable = False)
download_url = db.Column(db.String(200), nullable = False, default = '')
app_file_size = db.Column(db.Integer, nullable = False)
app_screen_size = db.Column(db.Integer, nullable = False)
app_screen_size = db.Column(db.String(20), nullable = False)
app_arch = db.Column(db.String(20), nullable = False, default = '')
app_review = db.Column(db.String(100), nullable = False, default = '')
app_review = db.Column(db.Integer, nullable = False, default = 0)
# __table_args__ = (
# db.Index('idx_xxx', 'xxx', mysql_using='btree'),
# )
def __init__(self, app_name, app_icon, app_version, category=0, category_2th=0, developer=0, download_url='', app_file_size=0, app_screen_size=0, app_arch='', app_review=''):
def __init__(self, app_name, app_icon, app_version, category='', category_2th='', developer=0, download_url='', app_file_size=0, app_screen_size='', app_arch='', app_review=0, create_by=None, create_at=None, update_by=None, update_at=None, remarks=""):
self.app_name = app_name
self.app_icon = app_icon
self.app_version = app_version
......@@ -35,11 +35,16 @@ class AppModel(PrimaryModel):
self.app_screen_size = app_screen_size
self.app_arch = app_arch
self.app_review = app_review
self.create_by = create_by
self.create_at = create_at
self.update_by = update_by
self.update_at = update_at
self.remarks = remarks
def __repr__(self):
return '<AppModel %r>' % (self.app_name)
def to_json(self):
def to_dict(self):
return {
'app_name': self.app_name,
'app_icon': self.app_icon,
......@@ -62,14 +67,16 @@ class PostAppSchema(ma.SQLAlchemySchema):
model = AppModel
app_name = ma.auto_field()
app_icon = ma.auto_field()
app_icon = fields.String(required=False)
app_version = ma.auto_field()
category = ma.auto_field()
category_2th = fields.String(required=False)
developer = fields.String(required=False)
app_screen_size = ma.auto_field()
app_arch = ma.auto_field()
app_review = ma.auto_field()
app_review = ma.auto_field(required=False)
logo = fields.Raw(required=False)
fileList = fields.Raw(required=False)
postAppSchema = PostAppSchema()
......
......@@ -24,7 +24,7 @@ class PackageModel(PrimaryModel):
# db.Index('idx_xxx', 'xxx', mysql_using='btree'),
# )
def __init__(self, app, app_version, package_info, algorithm='zlib', file_path='', source=0, user_agent='', download_url='', ip='127.0.0.1', geo_location='', operator='', create_by=None, create_at=None, update_by=None, update_at=None):
def __init__(self, app, app_version, package_info, algorithm='zlib', file_path='', source=0, user_agent='', download_url='', ip='127.0.0.1', geo_location='', operator='', create_by=None, create_at=None, update_by=None, update_at=None, remarks=""):
self.app = app
self.app_version = app_version
self.package_info = package_info
......@@ -40,6 +40,7 @@ class PackageModel(PrimaryModel):
self.create_at = create_at
self.update_by = update_by
self.update_at = update_at
self.remarks = remarks
def __repr__(self):
return '<PackageModel %r>' % (self.app)
......@@ -56,6 +57,7 @@ class PackageModel(PrimaryModel):
'ip': self.ip,
'geo_location': self.geo_location,
'operator': self.operator,
'remarks': self.remarks
}
......
import os
import traceback
from pathlib import Path
from datetime import datetime
from flask import current_app, jsonify, request
from flask_restful import Resource
from flask_restful.reqparse import RequestParser
from flask_jwt_extended import ( jwt_required, get_jwt_identity )
from werkzeug.datastructures import FileStorage
from werkzeug.utils import secure_filename
from application.config import config
from application.signal_manager import signalManager
......@@ -13,9 +16,8 @@ from webcreator.response import ResponseCode, response_result
class AppResourceList(Resource):
def __init__(self):
pass
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
# self.parser = RequestParser()
self.parser = RequestParser()
def get(self):
# 特殊参数,即不是从json获取参数的接口,可以将这个注释打开
......@@ -40,46 +42,65 @@ class AppResourceList(Resource):
@jwt_required(locations=["headers"])
def post(self):
self.parser.add_argument("app_name", type=str, location="form", required=True)
self.parser.add_argument("app_version", type=str, location="form", required=True)
self.parser.add_argument("category", type=str, location="form", required=True)
self.parser.add_argument("app_screen_size", type=str, location="form", required=True)
self.parser.add_argument("app_arch", type=str, location="form", required=True)
self.parser.add_argument("algorithm", type=str, location="form", required=True)
self.parser.add_argument("remarks", type=str, location="form", required=True)
self.parser.add_argument("logo", type=FileStorage, location="files", required=True)
self.parser.add_argument("fileList", type=FileStorage, location="files", required=True)
args = self.parser.parse_args()
try:
jwt = get_jwt_identity()
# 获取request.files参数
json_payload = request.json
params = postAppSchema.load(json_payload)
# json_payload = request.json
params = postAppSchema.load(args)
now_str = datetime.now().strftime("%Y%m%d%H%M%S")
# 获取相对路径
dirname = "{}-{}-{}-{}".format(params["app_name"], params["app_version"], params["category"], now_str)
relative_path = os.sep.join([config.EPK_DIR, dirname])
relative_path = Path(config.UPLOAD_ROOT_DIR)
logger.info(dirname)
# 获取最终存储的绝对路径
upload_path = os.path.normpath(os.sep.join([config.UPLOAD_ROOT_DIR, relative_path]))
upload_path = Path(config.EPK_DIR).joinpath(dirname)
# upload_path = os.path.normpath(os.sep.join([config.UPLOAD_ROOT_DIR, relative_path]))
if not os.path.exists(upload_path):
os.makedirs(upload_path)
logger.info(upload_path)
if not upload_path.exists():
os.makedirs(upload_path.resolve().as_posix())
files = []
# 应用logo
logo = request.files.get("logo")
logo = request.files.get("logo") # args.get('picture')
if logo:
filename = secure_filename(logo.filename)
file_path = os.sep.join([upload_path, filename])
file_path = os.path.normpath(file_path)
logger.info(filename)
# file_path = os.sep.join([upload_path, filename])
file_path = upload_path.joinpath(filename)
logo.save(file_path)
params.update({ "app_icon": file_path })
logger.info(file_path.resolve().as_posix())
params.update({ "app_icon": file_path.resolve().as_posix() })
# 应用源文件
fileList = request.files.getlist('fileList')
fileList = request.files.getlist('fileList') # args.get('picture')
if fileList:
upload_path = os.sep.join([upload_path, "src"])
if not os.path.exists(upload_path):
os.mkdir(upload_path)
# upload_path = os.sep.join([upload_path, "src"])
upload_path = upload_path.joinpath("src")
if not upload_path.exists():
logger.info(upload_path.resolve().as_posix())
os.mkdir(upload_path.resolve().as_posix())
for f in fileList:
filename = secure_filename(f.filename)
file_path = os.sep.join([upload_path, filename])
file_path = os.path.normpath(file_path)
f.save(file_path)
files.append(file_path)
# file_path = os.sep.join([upload_path, filename])
# file_path = os.path.normpath(file_path)
file_path = upload_path.joinpath(filename)
f.save(file_path.resolve().as_posix())
files.append(file_path.resolve().as_posix())
# obj = dict()
# obj['filename'] = binfile.filename
......@@ -92,6 +113,7 @@ class AppResourceList(Resource):
return response_result(ResponseCode.HTTP_SUCCESS, data=result, msg=message)
return response_result(message)
except Exception as e:
traceback.print_exc()
current_app.logger.error(e)
return response_result(ResponseCode.HTTP_SERVER_ERROR)
......
......@@ -363,15 +363,17 @@
},
{
"name": "category",
"dataType": "Integer",
"default": 0,
"dataType": "String",
"default": "''",
"length": 20,
"required": true,
"toJson": true
},
{
"name": "category_2th",
"dataType": "Integer",
"default": 0,
"dataType": "String",
"default": "''",
"length": 20,
"required": true,
"toJson": true
},
......@@ -385,7 +387,7 @@
{
"name": "download_url",
"dataType": "String",
"length": 20,
"length": 200,
"required": true,
"default": "''",
"toJson": true
......@@ -399,8 +401,9 @@
},
{
"name": "app_screen_size",
"dataType": "Integer",
"default": 0,
"dataType": "String",
"default": "''",
"length": 20,
"required": true,
"toJson": true
},
......@@ -414,10 +417,9 @@
},
{
"name": "app_review",
"dataType": "String",
"length": 100,
"dataType": "Integer",
"required": true,
"default": "''",
"default": 0,
"toJson": true
}
]
......
/*
* @Author: your name
* @Date: 2021-07-15 09:33:39
* @LastEditTime: 2021-07-15 21:15:15
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \evm-store\tools\frontend\src\utils\request.js
*/
import axios from 'axios';
import store from "@/store";
import { message } from "ant-design-vue";
import axios from "axios";
import { getToken } from "@/utils/auth";
// create an axios instance
......@@ -22,63 +12,44 @@ const service = axios.create({
// headers: {
// "Content-Type": "application/x-www-form-urlencoded;charset=utf-8"
// }
})
});
// request interceptor
service.interceptors.request.use(config => {
service.interceptors.request.use(
(config) => {
// Do something before request is sent
if (store.state.frontend.login.token) {
if (window.sessionStorage.getItem("Authorization")) {
// 让每个请求携带token-- ['Authorization']为自定义key 请根据实际情况自行修改
config.headers['Authorization'] = 'Bearer ' + getToken()
config.headers["Authorization"] = "Bearer " + getToken();
}
return config
}, error => {
return config;
},
(error) => {
// Do something with request error
// console.log('error', error) // for debug
Promise.reject(error)
})
Promise.reject(error);
}
);
// respone interceptor
service.interceptors.response.use(
response => {
// message.success('数据通讯完成', 1);
const { data } = response;
if (data) {
return data
}
return Promise.reject(response);
(response) => {
const res = response.data;
console.log(res)
// if (res.code === 200) return Promise.resolve(res);
// else if (res.code === 401) {
// store.dispatch("user/removeToken").then(() => {
// window.location.reload();
// });
// } else return Promise.reject(res);
return res;
},
error => {
/**
* 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
* 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
*/
// console.log('error', error)
const res = error.response;
if (res && res.data) {
const { code, msg } = res.data;
// 100401:非法的token; 100412:其他客户端登录了; 100413:Token 过期了;
if (code === 100401 || code === 100412 || code === 100413) {
// MessageBox.confirm('操作失败,原因:' + error + ',可以取消继续留在该页面,或者重新登录', '操作提示', {
// confirmButtonText: '重新登录',
// cancelButtonText: '取消',
// type: 'warning'
// }).then(() => {
// removeCookies(_CONST.TOKEN);
// location.reload();// 为了重新实例化vue-router对象 避免bug
// })
message.error(msg, 3);
} else {
let error;
if (!error) {
error = "请求失败,异常: " + res.statusText + ' [' + res.status + ']';
}
message.error(error, 5);
}
} else {
message.error("请求失败," + error, 5);
(error) => {
return Promise.reject(error);
}
return Promise.reject(error)
})
);
export default service
\ No newline at end of file
export default service;
......@@ -15,7 +15,7 @@
:labelCol="{ span: 7 }"
:wrapperCol="{ span: 10 }"
>
<a-radio-group v-model="post.algorithm" @change="onChange">
<a-radio-group v-model="post.algorithm">
<a-radio-button value="zlib"> zlib </a-radio-button>
<a-radio-button value="eheatshrink"> eheatshrink </a-radio-button>
</a-radio-group>
......@@ -39,7 +39,6 @@
mode="default"
style="width: 100%"
placeholder="应用所属类别"
@change="handleChange"
>
<a-select-option v-for="item in categoryList" :key="(item.value + 9).toString(36) + item.value">
{{ item.label }}
......@@ -57,8 +56,8 @@
list-type="picture-card"
class="avatar-uploader"
:show-upload-list="false"
:before-upload="beforeLogoUpload"
@change="handleChange"
:before-upload="beforeUpload"
@change="handleLogoChange"
>
<img v-if="imageUrl" :src="imageUrl" alt="avatar" />
<div v-else>
......@@ -153,6 +152,7 @@ import {
PageHeader,
DatePicker,
InputNumber,
message
} from "ant-design-vue";
import PageHeaderWrapper from "@/components/PageHeaderWrapper";
import DescriptionItem from "@/components/DescriptionItem";
......@@ -237,20 +237,24 @@ export default {
newFileList.splice(index, 1);
this.fileList = newFileList;
},
beforeLogoUpload(file) {
handleLogoChange(file) {
this.logo = file;
return false;
},
beforeUpload(file) {
if (file.size / 1024 / 1024 > 2) {
message.error("Image must smaller than 2MB!");
}
return false;
},
handleSourceFileChange(file) {
this.fileList = [...this.fileList, file];
const status = file.file.status;
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
this.$message.error("Image must smaller than 2MB!");
if (status === 'done') {
message.success(`${file.file.name} file uploaded successfully.`);
} else if (status === 'error') {
message.error(`${file.file.name} file upload failed.`);
}
return false;
},
handleUpload() {
this.uploading = true;
......@@ -268,36 +272,17 @@ export default {
this.postApplication(formData)
},
handleSourceFileChange(info) {
const status = info.file.status;
if (status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (status === 'done') {
this.$message.success(`${info.file.name} file uploaded successfully.`);
} else if (status === 'error') {
this.$message.error(`${info.file.name} file upload failed.`);
}
},
onChange(e) {
console.log(`checked = ${e.target.value}`);
},
handleChange(value) {
console.log(`selected ${value}`);
},
postApplication(formData) {
postApplication(formData).then(res => {
console.log(res)
this.fileList = [];
this.logo = null;
this.post.fileList = [];
this.post.logo = null;
// this.fileList = [];
// this.logo = null;
// this.post.fileList = [];
// this.post.logo = null;
this.uploading = false;
this.$message.success('upload successfully.');
message.success(res.msg);
}).catch(err => {
console.log(err)
this.uploading = false;
this.$message.error('upload failed.');
message.error(err.msg);
})
},
onSumbit() {
......
......@@ -165,7 +165,8 @@ export default {
.then((res) => {
this.$store.commit("frontend/login/setToken", res.data.token);
this.$store.commit("frontend/login/setUserInfo", { uuid: res.data.uuid, name: res.data.name });
message.success(res.msg)
message.success(res.msg);
window.sessionStorage.setItem("Authorization", res.data.token)
this.$router.push({ path: "/" });
})
.catch((err) => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment