下载页面增加举报功能

publicsignpoll
youngS 3 years ago
parent 20ac8eadda
commit 479abff102
  1. 1
      fir_client/public/short.html
  2. 222
      fir_client/src/components/FirDownload.vue
  3. 34
      fir_client/src/components/FirLogin.vue
  4. 34
      fir_client/src/components/FirRegist.vue
  5. 32
      fir_client/src/components/FirResetPwd.vue
  6. 370
      fir_client/src/components/ShortDownload.vue
  7. 41
      fir_client/src/components/user/FirUserProfileCertification.vue
  8. 35
      fir_client/src/components/user/FirUserProfileInfo.vue
  9. 26
      fir_client/src/main.short.js
  10. 155
      fir_client/src/restful/download.js
  11. 15
      fir_client/src/restful/index.js
  12. 4
      fir_client/src/utils/index.js
  13. 4
      fir_client/vue.config.js
  14. 2
      fir_ser/admin/views/login.py
  15. 21
      fir_ser/api/models.py
  16. 2
      fir_ser/api/urls.py
  17. 4
      fir_ser/api/utils/TokenManager.py
  18. 6
      fir_ser/api/utils/serializer.py
  19. 6
      fir_ser/api/utils/utils.py
  20. 71
      fir_ser/api/views/login.py
  21. 76
      fir_ser/api/views/report.py
  22. 20
      fir_ser/config.py
  23. 2
      fir_ser/fir_ser/settings.py

@ -5,6 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <link rel="icon" href="<%= BASE_URL %>favicon.ico">
<script src="<%= BASE_URL %>gt.js"></script>
<title>应用下载</title> <title>应用下载</title>
</head> </head>
<body> <body>

@ -2,6 +2,74 @@
<el-container class="container"> <el-container class="container">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0">
<el-main style="margin-top: -60px" v-if="report_flag">
<a style="color: #3888fa" @click="report_flag=false">&lt;&nbsp;返回下载页</a>
<el-header style="text-align: center;height: 20px;margin-top: 10px">举报详情</el-header>
<el-form>
<el-form-item>
<span>举报原因</span>
<el-select v-model="report_info.report_type" style="width: 100%">
<el-option v-for="item in report_info_list" :key="item.id" :label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item style="margin-top: -10px">
<span>详细原因</span>
<el-input type="textarea"
:rows="3"
v-model="report_info.report_reason"
placeholder="请详细说明举报原因"></el-input>
</el-form-item>
</el-form>
<el-divider/>
<el-form style="margin-top: -20px">
<el-header style="text-align: center;height: 20px">举报人信息填写</el-header>
<el-form-item>
<span>真实姓名</span>
<el-input v-model="report_info.username" placeholder="请输入您的姓名" clearable></el-input>
</el-form-item>
<el-form-item style="margin-top: -10px">
<span>联系信息</span>
<el-row>
<el-input v-model="report_info.email" :placeholder="`请输入您的${report_info_title}`"
clearable></el-input>
</el-row>
<el-row v-if="captcha.captcha_image" style="margin-top: 10px;margin-bottom: -10px">
<el-col :span="16">
<el-input placeholder="请输入图片验证码" v-model="report_info.authcode" maxlength="6" clearable/>
</el-col>
<el-col :span="8">
<el-image
style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px"
:src="captcha.captcha_image"
fit="contain" @click="get_auth_code">
</el-image>
</el-col>
</el-row>
<el-row style="margin-top: 10px">
<el-col :span="12">
<el-input v-model="report_info.seicode" prefix-icon="el-icon-mobile"
placeholder="验证码" clearable/>
</el-col>
<el-col :span="12">
<el-button type="info" @click="getphonecode" plain
style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px;width: 100%">
获取验证码
</el-button>
</el-col>
</el-row>
</el-form-item>
<el-form-item>
<div id="captcha" ref="captcha"></div>
</el-form-item>
<el-button style="width: 100%;height: 60px;" type="primary" plain @click="report_submit">立即举报
</el-button>
</el-form>
</el-main>
<div class="wechat_tip_content" v-if="(agent === 'wxandroid' || agent === 'wxapple') && !wrong"> <div class="wechat_tip_content" v-if="(agent === 'wxandroid' || agent === 'wxapple') && !wrong">
<div class="mask"> <div class="mask">
@ -19,7 +87,7 @@
<!-- <span class="pattern right"><img src="@/assets/down_right.png"></span>--> <!-- <span class="pattern right"><img src="@/assets/down_right.png"></span>-->
</div> </div>
<el-container class="out-container " v-if="wxeasytypeflag"> <el-container class="out-container " v-if="wxeasytypeflag && !report_flag">
<div class="main"> <div class="main">
<header> <header>
@ -220,7 +288,9 @@
<div class="footer" style="margin-top: 30%;margin-bottom: 8px"> <div class="footer" style="margin-top: 30%;margin-bottom: 8px">
免责声明<br> 免责声明<br>
本网站仅提供下载托管应用为用户自行上传请甄别应用风险后进行下载 本网站仅提供下载托管应用为用户自行上传请甄别应用风险后进行下载<a class="one-key-report"
@click="get_auth_code(),report_flag=true">举报</a>
</div> </div>
<div v-if="agent!==''"> <div v-if="agent!==''">
<div v-if="ad_info.ad_uri" style="margin-bottom: 80px"/> <div v-if="ad_info.ad_uri" style="margin-bottom: 80px"/>
@ -239,7 +309,7 @@
</el-container> </el-container>
<div v-else> <div v-else>
<i> <i v-if="!report_flag">
{{this.currentappinfo.name | formatName}} {{this.currentappinfo.name | formatName}}
</i> </i>
</div> </div>
@ -274,12 +344,37 @@
<script> <script>
import QRCode from 'qrcodejs2' import QRCode from 'qrcodejs2'
import {getdownloadurl, getShortAppinfo, gettask} from '@/restful' import {
getdownloadurl,
getShortAppinfo,
gettask,
getAuthTokenFun,
appReport,
checkEmail,
checkphone,
geetest
} from '@/restful/download'
export default { export default {
name: "FirDownload", name: "FirDownload",
data() { data() {
return { return {
captcha: {"captcha_image": '', "captcha_key": '', "length": 8},
report_info: {
'username': '',
'report_type': '',
'report_reason': '',
'seicode': '',
'authcode': '',
'email': '',
'auth_token': '',
'act': 'email',
},
report_info_title: '邮箱',
report_info_list: [
{'id': 0, name: '其他'},
],
report_flag: false,
signhelplist: [ signhelplist: [
{msg: '第一步 允许打开配置描述文件', url: require('@/assets/sign/step1.jpg')}, {msg: '第一步 允许打开配置描述文件', url: require('@/assets/sign/step1.jpg')},
{msg: '第二步 点击右上角安装按钮', url: require('@/assets/sign/step2.jpg')}, {msg: '第二步 点击右上角安装按钮', url: require('@/assets/sign/step2.jpg')},
@ -326,6 +421,117 @@
clearTimeout(this.timer); clearTimeout(this.timer);
}, },
methods: { methods: {
report_submit() {
let data = this.report_info;
data['app_id'] = this.currentappinfo.app_id;
if (this.report_info.auth_token && this.report_info.email && this.report_info.seicode) {
appReport(res => {
if (res.code === 1000) {
this.$message.success("信息提交成功,感谢您的支持,即将返回下载页");
// eslint-disable-next-line no-unused-vars
this.timer = setTimeout(data => {
this.report_flag = false;
}, 3000);
} else {
this.$message.error("信息提交失败,请稍后再试 " + res.msg)
}
}, {
'methods': 'POST',
'data': this.report_info
})
} else {
this.$message({
message: '请输入完整的信息',
type: 'warning'
});
}
},
getphonecode() {
if (!this.report_info.username || !this.report_info.report_reason || this.report_info.report_type === '') {
this.$message({
message: '请输入完整的信息',
type: 'warning'
});
return 0
}
if (this.report_info.act === 'email') {
if (!checkEmail(this.report_info.email)) {
this.$message({
message: '请输入正确的邮箱地址',
type: 'warning'
});
return 0
}
}
if (this.report_info.act === 'sms') {
if (!checkphone(this.report_info.email)) {
this.$message({
message: '请输入正确的手机号',
type: 'warning'
});
return 0
}
}
let picode = {
"authcode": this.report_info.authcode,
"captcha_key": this.captcha.captcha_key,
"report": this.currentappinfo.app_id
};
let params = {'act': this.report_info.act, 'target': this.report_info.email, 'ext': picode};
if (this.captcha.geetest) {
geetest(this, this.report_info.email, params, (n_params) => {
this.do_get_auth_token(n_params);
})
} else {
this.do_get_auth_token(params);
}
},
do_get_auth_token(params) {
getAuthTokenFun(data => {
if (data.code === 1000) {
this.$notify({
title: '验证码',
message: '验证码已经发送您',
type: 'success'
});
this.report_info.auth_token = data.data.auth_token;
} else {
this.$message({
message: data.msg,
type: 'error'
});
}
}, {"methods": 'POST', 'data': params})
},
get_auth_code() {
appReport(data => {
if (data.code === 1000) {
let jdata = data.data;
if (jdata.enable) {
this.captcha = data.data;
if (data.data.s_list) {
this.report_info_list = data.data.s_list;
}
if (jdata.report_type && jdata.report_type.sms) {
this.report_info_title = '手机号';
this.report_info.act = 'sms'
} else if (jdata.report_type && jdata.report_type.email) {
this.report_info_title = '邮箱';
this.report_info.act = 'email'
}
this.report_info.seicode = '';
this.report_info.auth_token = '';
return
}
}
this.$message.warning('暂未开通举报功能');
this.report_flag = false;
}, {
"methods": "GET",
"data": {}
});
},
show_err_msg(msg) { show_err_msg(msg) {
this.msg = msg; this.msg = msg;
this.$message({ this.$message({
@ -443,7 +649,6 @@
this.downloadurl = res.data.download_url; this.downloadurl = res.data.download_url;
} }
} }
window.location.href = this.downloadurl; window.location.href = this.downloadurl;
} else if (res.code === 1009) { } else if (res.code === 1009) {
this.isdownload = false; this.isdownload = false;
@ -714,6 +919,13 @@
</script> </script>
<style scoped> <style scoped>
.one-key-report {
color: #fff;
background-color: #32B2A7;
padding: 1px 5px;
border-radius: 15px;
}
.app_bottom_fixed { .app_bottom_fixed {
position: fixed; position: fixed;
bottom: 0; bottom: 0;

@ -32,7 +32,7 @@
</el-tabs> </el-tabs>
<el-form-item v-if="is_cptch"> <el-form-item v-if="is_captcha">
<el-input v-model="form.password" prefix-icon="el-icon-lock" placeholder="密码" <el-input v-model="form.password" prefix-icon="el-icon-lock" placeholder="密码"
@keyup.enter.native="onSubmit" @keyup.enter.native="onSubmit"
show-password clearable/> show-password clearable/>
@ -41,7 +41,7 @@
<el-input v-model="form.password" prefix-icon="el-icon-lock" placeholder="密码" <el-input v-model="form.password" prefix-icon="el-icon-lock" placeholder="密码"
show-password clearable/> show-password clearable/>
</el-form-item> </el-form-item>
<el-form-item style="height: 40px" v-if="cptch.cptch_image"> <el-form-item style="height: 40px" v-if="captcha.captcha_image">
<el-row style="height: 40px"> <el-row style="height: 40px">
<el-col :span="16"> <el-col :span="16">
<el-input placeholder="请输入验证码" v-model="form.authcode" maxlength="6" <el-input placeholder="请输入验证码" v-model="form.authcode" maxlength="6"
@ -50,7 +50,7 @@
<el-col :span="8"> <el-col :span="8">
<el-image <el-image
style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px" style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px"
:src="cptch.cptch_image" :src="captcha.captcha_image"
fit="contain" @click="get_auth_code"> fit="contain" @click="get_auth_code">
</el-image> </el-image>
</el-col> </el-col>
@ -114,7 +114,7 @@
password: '', password: '',
authcode: '' authcode: ''
}, },
cptch: {"cptch_image": '', "cptch_key": '', "length": 8}, captcha: {"captcha_image": '', "captcha_key": '', "length": 8},
activeName: 'username', activeName: 'username',
allow_ways: {'third': {}}, allow_ways: {'third': {}},
rutitle: '', rutitle: '',
@ -194,23 +194,23 @@
this.loop_flag = false; this.loop_flag = false;
} }
}, },
is_cptch() { is_captcha() {
let cptch_flag = this.form.authcode.length === this.cptch.length; let captcha_flag = this.form.authcode.length === this.captcha.length;
if (this.cptch.cptch_key === '' || !this.cptch.cptch_key) { if (this.captcha.captcha_key === '' || !this.captcha.captcha_key) {
cptch_flag = true captcha_flag = true
} }
return cptch_flag return captcha_flag
}, },
onSubmit() { onSubmit() {
let email = this.form.email; let email = this.form.email;
let password = this.form.password; let password = this.form.password;
let authcode = this.form.authcode; let authcode = this.form.authcode;
let login_type = 'up'; let login_type = 'up';
let cptch_flag = this.form.authcode.length === this.cptch.length; let captcha_flag = this.form.authcode.length === this.captcha.length;
if (this.cptch.cptch_key === '' || !this.cptch.cptch_key) { if (this.captcha.captcha_key === '' || !this.captcha.captcha_key) {
cptch_flag = true captcha_flag = true
} }
if (cptch_flag) { if (captcha_flag) {
if (this.activeName === "username") { if (this.activeName === "username") {
if (email.length < 6) { if (email.length < 6) {
@ -248,12 +248,12 @@
"username": email, "username": email,
"password": password, "password": password,
"authcode": authcode, "authcode": authcode,
"cptch_key": this.cptch.cptch_key, "captcha_key": this.captcha.captcha_key,
"login_type": login_type, "login_type": login_type,
}; };
this.login_disable = true; this.login_disable = true;
if (this.cptch.geetest) { if (this.captcha.geetest) {
geetest(this, params, (n_params) => { geetest(this, this.form.email, params, (n_params) => {
this.do_login(n_params); this.do_login(n_params);
}) })
} else { } else {
@ -317,7 +317,7 @@
get_auth_code() { get_auth_code() {
loginFun(data => { loginFun(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.cptch = data.data; this.captcha = data.data;
this.allow_ways = data.data.login_type; this.allow_ways = data.data.login_type;
this.register_enable = data.data.register_enable; this.register_enable = data.data.register_enable;
this.form.authcode = ''; this.form.authcode = '';

@ -26,7 +26,7 @@
clearable/> clearable/>
</el-form-item> </el-form-item>
<el-form-item style="height: 40px" v-if="cptch.cptch_image"> <el-form-item style="height: 40px" v-if="captcha.captcha_image">
<el-row style="height: 40px"> <el-row style="height: 40px">
<el-col :span="16"> <el-col :span="16">
<el-input placeholder="请输入图片验证码" v-model="form.authcode" maxlength="6" clearable/> <el-input placeholder="请输入图片验证码" v-model="form.authcode" maxlength="6" clearable/>
@ -34,7 +34,7 @@
<el-col :span="8"> <el-col :span="8">
<el-image <el-image
style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px" style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px"
:src="cptch.cptch_image" :src="captcha.captcha_image"
fit="contain" @click="get_auth_code"> fit="contain" @click="get_auth_code">
</el-image> </el-image>
</el-col> </el-col>
@ -106,7 +106,7 @@
auth_token: '', auth_token: '',
}, },
cptch: {"cptch_image": '', "cptch_key": '', "length": 8}, captcha: {"captcha_image": '', "captcha_key": '', "length": 8},
allow_r: false, allow_r: false,
allow_ways: {}, allow_ways: {},
rutitle: '', rutitle: '',
@ -134,7 +134,7 @@
this.allow_ways = jdata.register_type; this.allow_ways = jdata.register_type;
this.form.authcode = ''; this.form.authcode = '';
this.set_rtitle(); this.set_rtitle();
this.cptch = data.data; this.captcha = data.data;
} else { } else {
this.allow_r = false; this.allow_r = false;
this.$message({ this.$message({
@ -182,19 +182,19 @@
act = 'email' act = 'email'
} }
let authcode = this.form.authcode; let authcode = this.form.authcode;
let cptch_flag = authcode.length === this.cptch.length; let captcha_flag = authcode.length === this.captcha.length;
if (this.cptch.cptch_key === '' || !this.cptch.cptch_key) { if (this.captcha.captcha_key === '' || !this.captcha.captcha_key) {
cptch_flag = true captcha_flag = true
} }
if (cptch_flag) { if (captcha_flag) {
let picode = { let picode = {
"authcode": authcode, "authcode": authcode,
"cptch_key": this.cptch.cptch_key, "captcha_key": this.captcha.captcha_key,
"icode": this.form.icode, "icode": this.form.icode,
}; };
let params = {'act': act, 'target': this.form.email, 'ext': picode}; let params = {'act': act, 'target': this.form.email, 'ext': picode};
if (this.cptch.geetest) { if (this.captcha.geetest) {
geetest(this, params, (n_params) => { geetest(this, this.form.email, params, (n_params) => {
this.do_get_auth_token(n_params); this.do_get_auth_token(n_params);
}) })
} else { } else {
@ -278,11 +278,11 @@
return return
} }
let authcode = this.form.authcode; let authcode = this.form.authcode;
let cptch_flag = authcode.length === this.cptch.length; let captcha_flag = authcode.length === this.captcha.length;
if (this.cptch.cptch_key === '' || !this.cptch.cptch_key) { if (this.captcha.captcha_key === '' || !this.captcha.captcha_key) {
cptch_flag = true captcha_flag = true
} }
if (cptch_flag) { if (captcha_flag) {
if (password === password2 && password.length >= 6) { if (password === password2 && password.length >= 6) {
let params = { let params = {
"username": email, "username": email,
@ -292,8 +292,8 @@
"auth_key": this.form.seicode "auth_key": this.form.seicode
}; };
this.register_disable = true; this.register_disable = true;
if (this.cptch.geetest) { if (this.captcha.geetest) {
geetest(this, params, (n_params) => { geetest(this, this.form.email, params, (n_params) => {
this.do_register(n_params); this.do_register(n_params);
}) })
} else { } else {

@ -17,7 +17,7 @@
<el-input v-model="form.email" prefix-icon="el-icon-user" placeholder="邮箱或手机号" autofocus <el-input v-model="form.email" prefix-icon="el-icon-user" placeholder="邮箱或手机号" autofocus
clearable/> clearable/>
</el-form-item> </el-form-item>
<el-form-item style="height: 40px" v-if="cptch.cptch_image"> <el-form-item style="height: 40px" v-if="captcha.captcha_image">
<el-row style="height: 40px"> <el-row style="height: 40px">
<el-col :span="16"> <el-col :span="16">
<el-input placeholder="请输入验证码" v-model="form.authcode" maxlength="6" <el-input placeholder="请输入验证码" v-model="form.authcode" maxlength="6"
@ -26,7 +26,7 @@
<el-col :span="8"> <el-col :span="8">
<el-image <el-image
style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px" style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px"
:src="cptch.cptch_image" :src="captcha.captcha_image"
fit="contain" @click="get_auth_code"> fit="contain" @click="get_auth_code">
</el-image> </el-image>
</el-col> </el-col>
@ -85,7 +85,7 @@
seicode: '', seicode: '',
auth_token: '' auth_token: ''
}, },
cptch: {"cptch_image": '', "cptch_key": '', "length": 8}, captcha: {"captcha_image": '', "captcha_key": '', "length": 8},
activeName: 'username', activeName: 'username',
allow_ways: {}, allow_ways: {},
rutitle: '', rutitle: '',
@ -107,28 +107,28 @@
this.$message.error("输入有误,请检查") this.$message.error("输入有误,请检查")
} }
}, },
is_cptch() { is_captcha() {
let cptch_flag = this.form.authcode.length === this.cptch.length; let captcha_flag = this.form.authcode.length === this.captcha.length;
if (this.cptch.cptch_key === '' || !this.cptch.cptch_key) { if (this.captcha.captcha_key === '' || !this.captcha.captcha_key) {
cptch_flag = true captcha_flag = true
} }
return cptch_flag return captcha_flag
}, },
onSubmit() { onSubmit() {
let email = this.form.email; let email = this.form.email;
let authcode = this.form.authcode; let authcode = this.form.authcode;
let cptch_flag = this.form.authcode.length === this.cptch.length; let captcha_flag = this.form.authcode.length === this.captcha.length;
if (this.cptch.cptch_key === '' || !this.cptch.cptch_key) { if (this.captcha.captcha_key === '' || !this.captcha.captcha_key) {
cptch_flag = true captcha_flag = true
} }
if (cptch_flag) { if (captcha_flag) {
let checke = checkEmail(this.form.email); let checke = checkEmail(this.form.email);
let checkp = checkphone(this.form.email); let checkp = checkphone(this.form.email);
if (checke || checkp) { if (checke || checkp) {
let params = { let params = {
"username": email, "username": email,
"authcode": authcode, "authcode": authcode,
"cptch_key": this.cptch.cptch_key, "captcha_key": this.captcha.captcha_key,
"login_type": 'reset', "login_type": 'reset',
}; };
let seicode = this.form.seicode; let seicode = this.form.seicode;
@ -140,8 +140,8 @@
params['auth_token'] = auth_token params['auth_token'] = auth_token
} }
this.login_disable = true; this.login_disable = true;
if (this.cptch.geetest) { if (this.captcha.geetest) {
geetest(this, params, (n_params) => { geetest(this, this.form.email, params, (n_params) => {
this.do_login(n_params); this.do_login(n_params);
}) })
} else { } else {
@ -196,7 +196,7 @@
get_auth_code() { get_auth_code() {
loginFun(data => { loginFun(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.cptch = data.data; this.captcha = data.data;
this.register_enable = data.data.register_enable; this.register_enable = data.data.register_enable;
this.form.authcode = ''; this.form.authcode = '';
} else { } else {

@ -2,6 +2,70 @@
<div class="container"> <div class="container">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0">
<div style="margin-top: -60px" v-if="report_flag" class="one-key-report-dialog dialog">
<a style="color: #3888fa" @click="report_flag=false">&lt;&nbsp;返回下载页</a>
<header style="text-align: center;height: 20px;margin-top: 10px">举报详情</header>
<div>
<div class="content-row">
<span>举报原因</span>
<select v-model="report_info.report_type" style="width: 100%" class="report_select">
<option v-for="item in report_info_list" :key="item.id" :label="item.name"
:value="item.id">
</option>
</select>
</div>
<div class="content-row">
<span>详细原因</span>
<textarea v-model="report_info.report_reason" placeholder="请详细说明举报原因"/>
</div>
</div>
<br/>
<div>
<div class="content-row">
<header style="text-align: center;height: 40px">举报人信息填写</header>
<div>
<span>真实姓名</span>
<label>
<input v-model="report_info.username" placeholder="请输入您的姓名"/>
</label>
</div>
</div>
<div class="content-row">
<span>联系信息</span>
<div>
<label>
<input v-model="report_info.email" :placeholder="`请输入您的${report_info_title}`"/>
</label>
</div>
</div>
<div class="content-row">
<div v-if="captcha.captcha_image" class="report_captcha">
<input placeholder="请输入图片验证码" v-model="report_info.authcode" maxlength="6" type="text"/>
<img :src="captcha.captcha_image" fit="contain" @click="get_auth_code"/>
</div>
<div class="report_phone">
<input v-model="report_info.seicode"
placeholder="验证码"/>
<button class="btn" @click="getphonecode">
获取验证码
</button>
</div>
</div>
</div>
<div class="content-row">
<div id="captcha" ref="captcha"></div>
</div>
<div class="content-row" style="text-align: center">
<button class="btn-report" @click="report_submit">立即举报</button>
</div>
</div>
<div ref="signhelp" class="signhelp screenshots-section"> <div ref="signhelp" class="signhelp screenshots-section">
<div class="signhelp-title"> <div class="signhelp-title">
iOS安装教程 iOS安装教程
@ -40,7 +104,7 @@
<!-- <span class="pattern right"><img src="@/assets/download_pattern_right.png"></span>--> <!-- <span class="pattern right"><img src="@/assets/download_pattern_right.png"></span>-->
</div> </div>
<div class="out-container " v-if="wxeasytypeflag"> <div class="out-container " v-if="wxeasytypeflag && !report_flag">
<div v-show='mcurrentappinfo.release_id' class="main"> <div v-show='mcurrentappinfo.release_id' class="main">
<header> <header>
@ -234,7 +298,8 @@
<div class="footer" style="margin-top: 30%;margin-bottom: 8px"> <div class="footer" style="margin-top: 30%;margin-bottom: 8px">
免责声明<br> 免责声明<br>
本网站仅提供下载托管应用为用户自行上传请甄别应用风险后进行下载 本网站仅提供下载托管应用为用户自行上传请甄别应用风险后进行下载<a class="one-key-report"
@click="get_auth_code(),report_flag=true">举报</a>
</div> </div>
<div v-if="agent!==''"> <div v-if="agent!==''">
<div v-if="ad_info.ad_uri" style="margin-bottom: 80px"/> <div v-if="ad_info.ad_uri" style="margin-bottom: 80px"/>
@ -253,7 +318,7 @@
</div> </div>
<div v-else> <div v-else>
<i> <i v-if="!report_flag">
{{this.currentappinfo.name | formatName}} {{this.currentappinfo.name | formatName}}
</i> </i>
</div> </div>
@ -273,12 +338,29 @@
<script> <script>
import QRCode from 'qrcodejs2' import QRCode from 'qrcodejs2'
import {getdownloadurl, getShortAppinfo, gettask} from '@/restful/download' import {getdownloadurl, getShortAppinfo, gettask, getAuthTokenFun, appReport} from '@/restful/download'
import {checkEmail, checkphone, geetest} from "@/restful/download";
export default { export default {
name: "ShortDownload", name: "ShortDownload",
data() { data() {
return { return {
captcha: {"captcha_image": '', "captcha_key": '', "length": 8},
report_info: {
'username': '',
'report_type': '',
'report_reason': '',
'seicode': '',
'authcode': '',
'email': '',
'auth_token': '',
'act': 'email',
},
report_info_title: '邮箱',
report_info_list: [
{'id': 0, name: '其他'},
],
report_flag: false,
signhelplist: [ signhelplist: [
{msg: '第一步 允许打开配置描述文件', url: require('@/assets/sign/step1.jpg')}, {msg: '第一步 允许打开配置描述文件', url: require('@/assets/sign/step1.jpg')},
{msg: '第二步 点击右上角安装按钮', url: require('@/assets/sign/step2.jpg')}, {msg: '第二步 点击右上角安装按钮', url: require('@/assets/sign/step2.jpg')},
@ -327,6 +409,98 @@
clearTimeout(this.timer); clearTimeout(this.timer);
}, },
methods: { methods: {
report_submit() {
let data = this.report_info;
data['app_id'] = this.currentappinfo.app_id;
if (this.report_info.auth_token && this.report_info.email && this.report_info.seicode) {
appReport(res => {
if (res.code === 1000) {
alert("信息提交成功,感谢您的支持,即将返回下载页");
// eslint-disable-next-line no-unused-vars
this.timer = setTimeout(data => {
this.report_flag = false;
}, 3000);
} else {
alert("信息提交失败,请稍后再试 " + res.msg)
}
}, {
'methods': 'POST',
'data': this.report_info
})
} else {
alert('请输入完整的信息');
}
},
getphonecode() {
if (!this.report_info.username || !this.report_info.report_reason || this.report_info.report_type === '') {
alert('请输入完整的信息');
return 0
}
if (this.report_info.act === 'email') {
if (!checkEmail(this.report_info.email)) {
alert('请输入正确的邮箱地址');
return 0
}
}
if (this.report_info.act === 'sms') {
if (!checkphone(this.report_info.email)) {
alert('请输入正确的手机号');
return 0
}
}
let picode = {
"authcode": this.report_info.authcode,
"captcha_key": this.captcha.captcha_key,
"report": this.currentappinfo.app_id
};
let params = {'act': this.report_info.act, 'target': this.report_info.email, 'ext': picode};
if (this.captcha.geetest) {
geetest(this, this.report_info.email, params, (n_params) => {
this.do_get_auth_token(n_params);
})
} else {
this.do_get_auth_token(params);
}
},
do_get_auth_token(params) {
getAuthTokenFun(data => {
if (data.code === 1000) {
alert('验证码已经发送您');
this.report_info.auth_token = data.data.auth_token;
} else {
alert(data.msg);
}
}, {"methods": 'POST', 'data': params})
},
get_auth_code() {
appReport(data => {
if (data.code === 1000) {
let jdata = data.data;
if (jdata.enable) {
this.captcha = data.data;
if (data.data.s_list) {
this.report_info_list = data.data.s_list;
}
if (jdata.report_type && jdata.report_type.sms) {
this.report_info_title = '手机号';
this.report_info.act = 'sms'
} else if (jdata.report_type && jdata.report_type.email) {
this.report_info_title = '邮箱';
this.report_info.act = 'email'
}
this.report_info.seicode = '';
this.report_info.auth_token = '';
return
}
}
alert('暂未开通举报功能');
this.report_flag = false;
}, {
"methods": "GET",
"data": {}
});
},
show_err_msg(msg) { show_err_msg(msg) {
this.msg = msg; this.msg = msg;
alert(this.msg) alert(this.msg)
@ -702,6 +876,178 @@
</script> </script>
<style scoped> <style scoped>
.dialog {
position: fixed;
width: 390px;
background-color: #fff;
left: 50%;
top: 50%;
z-index: 99999;
padding: 20px;
box-shadow: 0 0 5px rgba(0, 0, 0, .5);
transform: translate(-50%, -50%)
}
.one-key-report-dialog .content-row {
display: table;
padding: 5px;
position: relative;
width: 100%
}
.one-key-report-dialog .report_select {
position: relative;
width: 100%;
height: 50px;
border: 1px solid #D6D6D6;
font-size: 14px;
line-height: 50px;
text-indent: 15px;
cursor: pointer
}
.one-key-report-dialog .report_select:hover {
background: #F5F5F5
}
.one-key-report-dialog .report_select .dropdown-menu > option {
line-height: 40px;
cursor: pointer
}
.one-key-report-dialog .report_select .dropdown-menu > option:hover {
color: #fff;
background: #42B191
}
.one-key-report-dialog .content-row {
display: table;
padding: 5px;
position: relative;
width: 100%
}
.one-key-report-dialog .content-row input, .one-key-report-dialog .content-row label {
display: block
}
.one-key-report-dialog .content-row label {
color: #666;
font-size: 18px;
line-height: 34px;
margin-right: 30px
}
.one-key-report-dialog .content-row input {
height: 50px;
width: 100%;
margin-bottom: 10px;
padding: 5px 10px;
outline: 0;
background: #F5F5F5;
font-size: 14px;
border: 1px solid #D6D6D6
}
.one-key-report-dialog .content-row input::-moz-placeholder {
font-size: 14px;
color: #8B8E93
}
.one-key-report-dialog .content-row input:-ms-input-placeholder {
font-size: 14px;
color: #8B8E93
}
.one-key-report-dialog .content-row input::placeholder {
font-size: 14px;
color: #8B8E93
}
.one-key-report-dialog .content-row .report_captcha {
display: -ms-flexbox;
display: flex
}
.one-key-report-dialog .content-row .report_captcha input {
display: inline-block;
width: 190px;
margin-right: 20px
}
.one-key-report-dialog .content-row .report_captcha img {
width: 125px;
height: 50px;
background: #F5F5F5;
cursor: pointer
}
.one-key-report-dialog .content-row .report_phone input {
display: inline-block;
width: 190px;
margin-right: 20px
}
.one-key-report-dialog .content-row .report_phone .btn {
width: 125px;
color: #fff;
height: 50px;
background-color: #3888fa;
padding: 5px 10px;
margin-top: -5px;
font-size: 14px
}
.one-key-report-dialog .content-row textarea {
width: 100%;
height: 80px;
resize: none;
padding: 10px;
outline: 0;
color: #A9B1B3;
font-size: 14px;
background: #F5F5F5;
border: 1px solid #D6D6D6;
}
.one-key-report-dialog .content-row textarea::-moz-placeholder {
font-size: 14px;
color: #8B8E93
}
.one-key-report-dialog .content-row textarea:-ms-input-placeholder {
font-size: 14px;
color: #8B8E93
}
.one-key-report-dialog .content-row textarea::placeholder {
font-size: 14px;
color: #8B8E93
}
.one-key-report-dialog .content-row .btn-report {
color: #fff;
background-color: #3888fa;
padding: 5px 10px;
margin-top: 5px;
width: 190px;
height: 50px;
display: inline-block;
line-height: 40px;
font-size: 18px
}
.one-key-report {
color: #fff;
background-color: #32B2A7;
padding: 1px 5px;
border-radius: 15px;
}
.el-tag { .el-tag {
background-color: #ecf5ff; background-color: #ecf5ff;
border-color: #d9ecff; border-color: #d9ecff;
@ -1234,6 +1580,22 @@
.main > header .scan-tips { .main > header .scan-tips {
display: none display: none
} }
.dialog {
height: 100%;
margin: 0;
left: 0;
top: 60px;
bottom: 0;
border-radius: 0;
padding-top: 30px;
overflow-y: auto;
transform: translate(0, 0)
}
.dialog.animate {
transition: left .5s
}
} }

@ -100,7 +100,7 @@
</el-form-item> </el-form-item>
<el-form-item label="手机号码" v-if="cptch.change_type.sms"> <el-form-item label="手机号码" v-if="captcha.change_type.sms">
<el-row :gutter="36"> <el-row :gutter="36">
<el-col :span="18"> <el-col :span="18">
<el-input v-model="form.mobile" ref="phone" clearable <el-input v-model="form.mobile" ref="phone" clearable
@ -108,7 +108,7 @@
</el-col> </el-col>
</el-row> </el-row>
</el-form-item> </el-form-item>
<el-form-item label="图片验证码" v-if="cptch.cptch_image"> <el-form-item label="图片验证码" v-if="captcha.captcha_image">
<el-row :gutter="11"> <el-row :gutter="11">
<el-col :span="12"> <el-col :span="12">
<el-input placeholder="请输入图片验证码" v-model="form.authcode" maxlength="6" clearable/> <el-input placeholder="请输入图片验证码" v-model="form.authcode" maxlength="6" clearable/>
@ -116,14 +116,14 @@
<el-col :span="6"> <el-col :span="6">
<el-image <el-image
style="border-radius:4px;cursor:pointer;height: 40px" style="border-radius:4px;cursor:pointer;height: 40px"
:src="cptch.cptch_image" :src="captcha.captcha_image"
fit="contain" @click="get_auth_code"> fit="contain" @click="get_auth_code">
</el-image> </el-image>
</el-col> </el-col>
</el-row> </el-row>
</el-form-item> </el-form-item>
<el-form-item label="手机验证码" v-if="cptch.change_type.sms"> <el-form-item label="手机验证码" v-if="captcha.change_type.sms">
<el-row :gutter="11"> <el-row :gutter="11">
<el-col :span="12"> <el-col :span="12">
<el-input v-model="form.auth_key" prefix-icon="el-icon-mobile" placeholder="请输入您收到的验证码" <el-input v-model="form.auth_key" prefix-icon="el-icon-mobile" placeholder="请输入您收到的验证码"
@ -220,16 +220,16 @@
<script> <script>
import {changeInfoFun, getAuthcTokenFun, user_certification} from "@/restful"; import {changeInfoFun, getAuthcTokenFun, user_certification} from "@/restful";
import {AvatarUploadUtils, checkphone, geetest, getUserInfoFun} from "@/utils"; import {AvatarUploadUtils, getUserInfoFun, checkphone, geetest} from "@/utils";
export default { export default {
name: "FirUserProfileCertification", name: "FirUserProfileCertification",
data() { data() {
return { return {
form: {}, form: {},
cptch: { captcha: {
cptch_image: '', captcha_image: '',
cptch_key: '', captcha_key: '',
authcode: '', authcode: '',
length: 8, length: 8,
change_type: {email: false, sms: false} change_type: {email: false, sms: false}
@ -262,7 +262,7 @@
this.$message.error("身份证输入不合法"); this.$message.error("身份证输入不合法");
return false; return false;
} }
if (this.cptch.change_type.sms) { if (this.captcha.change_type.sms) {
let checkp = checkphone(this.form.mobile); let checkp = checkphone(this.form.mobile);
if (!checkp) { if (!checkp) {
this.$message.error("手机号输入不合法"); this.$message.error("手机号输入不合法");
@ -305,18 +305,18 @@
getsmsemailcode(act, target) { getsmsemailcode(act, target) {
let picode = { let picode = {
"authcode": this.form.authcode, "authcode": this.form.authcode,
"cptch_key": this.cptch.cptch_key, "captcha_key": this.captcha.captcha_key,
}; };
if (this.cptch.cptch_image) { if (this.captcha.captcha_image) {
if (!this.form.authcode) { if (!this.form.authcode) {
this.$message.error("图片验证码输入有误"); this.$message.error("图片验证码输入有误");
return; return;
} }
let cptch_flag = this.form.authcode.length === this.cptch.length; let captcha_flag = this.form.authcode.length === this.captcha.length;
if (this.cptch.cptch_key === '' || !this.cptch.cptch_key) { if (this.captcha.captcha_key === '' || !this.captcha.captcha_key) {
cptch_flag = true captcha_flag = true
} }
if (!cptch_flag) { if (!captcha_flag) {
this.$message.error("图片验证码输入有误"); this.$message.error("图片验证码输入有误");
return return
} }
@ -329,9 +329,8 @@
} }
let params = {'act': act, 'target': target, 'ext': picode, 'user_id': target, 'ftype': 'certification'}; let params = {'act': act, 'target': target, 'ext': picode, 'user_id': target, 'ftype': 'certification'};
if (this.cptch.geetest) { if (this.captcha.geetest) {
this.form.email = this.form.mobile; geetest(this, this.form.mobile, params, (n_params) => {
geetest(this, params, (n_params) => {
this.get_phone_code(n_params); this.get_phone_code(n_params);
}) })
} else { } else {
@ -363,9 +362,9 @@
} }
changeInfoFun(data => { changeInfoFun(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.cptch = data.data; this.captcha = data.data;
if (this.cptch.cptch_key) { if (this.captcha.captcha_key) {
this.form.cptch_key = this.cptch.cptch_key; this.form.captcha_key = this.captcha.captcha_key;
} }
} else { } else {
this.$message({ this.$message({

@ -109,13 +109,13 @@
<el-col :span="16"> <el-col :span="16">
<el-input v-model="userinfo.mobile" ref="phone" :readonly="editphone !== true" <el-input v-model="userinfo.mobile" ref="phone" :readonly="editphone !== true"
prefix-icon="el-icon-mobile" placeholder="手机" maxlength="11" clearable prefix-icon="el-icon-mobile" placeholder="手机" maxlength="11" clearable
:disabled="!cptch.change_type.sms"/> :disabled="!captcha.change_type.sms"/>
</el-col> </el-col>
<el-col :span="1"> <el-col :span="1">
<el-button icon="el-icon-edit" @click="changePhoneValue"> <el-button icon="el-icon-edit" @click="changePhoneValue">
</el-button> </el-button>
</el-col> </el-col>
<el-col :span="5" v-if="editphone === true && cptch.change_type.sms"> <el-col :span="5" v-if="editphone === true && captcha.change_type.sms">
<el-button type="success" @click="savePhone" plain <el-button type="success" @click="savePhone" plain
class="save-button"> class="save-button">
保存 保存
@ -125,7 +125,7 @@
</el-form-item> </el-form-item>
<el-form-item label="图片验证码" style="height: 40px" <el-form-item label="图片验证码" style="height: 40px"
v-if="editphone === true && cptch.cptch_image && cptch.change_type.sms"> v-if="editphone === true && captcha.captcha_image && captcha.change_type.sms">
<el-row style="height: 40px" :gutter="36"> <el-row style="height: 40px" :gutter="36">
<el-col :span="14"> <el-col :span="14">
<el-input placeholder="请输入图片验证码" v-model="userinfo.authcode" maxlength="6" clearable/> <el-input placeholder="请输入图片验证码" v-model="userinfo.authcode" maxlength="6" clearable/>
@ -133,14 +133,14 @@
<el-col :span="8"> <el-col :span="8">
<el-image <el-image
style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px" style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px"
:src="cptch.cptch_image" :src="captcha.captcha_image"
fit="contain" @click="get_auth_code"> fit="contain" @click="get_auth_code">
</el-image> </el-image>
</el-col> </el-col>
</el-row> </el-row>
</el-form-item> </el-form-item>
<el-form-item label="手机验证码" v-if="editphone === true && cptch.change_type.sms"> <el-form-item label="手机验证码" v-if="editphone === true && captcha.change_type.sms">
<el-row :gutter="36"> <el-row :gutter="36">
<el-col :span="16"> <el-col :span="16">
<el-input v-model="userinfo.auth_key" prefix-icon="el-icon-mobile" placeholder="验证码" <el-input v-model="userinfo.auth_key" prefix-icon="el-icon-mobile" placeholder="验证码"
@ -162,13 +162,13 @@
<el-col :span="16"> <el-col :span="16">
<el-input v-model="userinfo.email" ref="email" :readonly="editemail !== true" <el-input v-model="userinfo.email" ref="email" :readonly="editemail !== true"
prefix-icon="el-icon-bank-card" placeholder="邮箱" maxlength="20" clearable prefix-icon="el-icon-bank-card" placeholder="邮箱" maxlength="20" clearable
:disabled="!cptch.change_type.email"/> :disabled="!captcha.change_type.email"/>
</el-col> </el-col>
<el-col :span="1"> <el-col :span="1">
<el-button icon="el-icon-edit" @click="changeemailValue"> <el-button icon="el-icon-edit" @click="changeemailValue">
</el-button> </el-button>
</el-col> </el-col>
<el-col :span="5" v-if="editemail === true && cptch.change_type.email"> <el-col :span="5" v-if="editemail === true && captcha.change_type.email">
<el-button type="success" @click="saveemail" plain <el-button type="success" @click="saveemail" plain
class="save-button"> class="save-button">
保存 保存
@ -179,7 +179,7 @@
<el-form-item label="图片验证码" style="height: 40px" <el-form-item label="图片验证码" style="height: 40px"
v-if="editemail === true && cptch.cptch_image && cptch.change_type.email"> v-if="editemail === true && captcha.captcha_image && captcha.change_type.email">
<el-row style="height: 40px" :gutter="36"> <el-row style="height: 40px" :gutter="36">
<el-col :span="14"> <el-col :span="14">
<el-input placeholder="请输入图片验证码" v-model="userinfo.authcode" maxlength="6" clearable/> <el-input placeholder="请输入图片验证码" v-model="userinfo.authcode" maxlength="6" clearable/>
@ -187,14 +187,14 @@
<el-col :span="8"> <el-col :span="8">
<el-image <el-image
style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px" style="margin:0 4px;border-radius:4px;cursor:pointer;height: 40px"
:src="cptch.cptch_image" :src="captcha.captcha_image"
fit="contain" @click="get_auth_code"> fit="contain" @click="get_auth_code">
</el-image> </el-image>
</el-col> </el-col>
</el-row> </el-row>
</el-form-item> </el-form-item>
<el-form-item label="邮箱验证码" v-if="editemail === true && cptch.change_type.email"> <el-form-item label="邮箱验证码" v-if="editemail === true && captcha.change_type.email">
<el-row :gutter="36"> <el-row :gutter="36">
<el-col :span="16"> <el-col :span="16">
<el-input v-model="userinfo.auth_key" prefix-icon="el-icon-mobile" placeholder="验证码" <el-input v-model="userinfo.auth_key" prefix-icon="el-icon-mobile" placeholder="验证码"
@ -295,7 +295,7 @@
editdomain_name: false, editdomain_name: false,
edituser_name: false, edituser_name: false,
editposition: false, editposition: false,
cptch: {"cptch_image": '', "cptch_key": '', "length": 8, change_type: {email: false, sms: false}}, captcha: {"captcha_image": '', "captcha_key": '', "length": 8, change_type: {email: false, sms: false}},
form: {}, form: {},
wx_login_qr_url: '', wx_login_qr_url: '',
wx_visible: false, wx_visible: false,
@ -408,8 +408,8 @@
get_auth_code() { get_auth_code() {
changeInfoFun(data => { changeInfoFun(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.cptch = data.data; this.captcha = data.data;
this.userinfo.cptch_key = this.cptch.cptch_key; this.userinfo.captcha_key = this.captcha.captcha_key;
if (this.userinfo.authcode) { if (this.userinfo.authcode) {
this.userinfo.authcode = ''; this.userinfo.authcode = '';
} }
@ -445,7 +445,7 @@
return { return {
auth_token: this.userinfo.auth_token, auth_token: this.userinfo.auth_token,
auth_key: this.userinfo.auth_key, auth_key: this.userinfo.auth_key,
cptch_key: this.userinfo.cptch_key, captcha_key: this.userinfo.captcha_key,
authcode: this.userinfo.authcode, authcode: this.userinfo.authcode,
}; };
}, },
@ -554,14 +554,13 @@
getsmsemailcode(act, target) { getsmsemailcode(act, target) {
let picode = { let picode = {
"authcode": this.userinfo.authcode, "authcode": this.userinfo.authcode,
"cptch_key": this.cptch.cptch_key, "captcha_key": this.captcha.captcha_key,
}; };
let params = { let params = {
'act': act, 'target': target, 'ext': picode 'act': act, 'target': target, 'ext': picode
}; };
if (this.cptch.geetest) { if (this.captcha.geetest) {
this.form.email = target; geetest(this, this.form.email, target, params, (n_params) => {
geetest(this, params, (n_params) => {
this.do_get_auth_token(n_params); this.do_get_auth_token(n_params);
}) })
} else { } else {

@ -3,7 +3,23 @@ import Download from "@/Download";
import router from "@/router/download"; import router from "@/router/download";
import 'element-ui/lib/theme-chalk/index.css' import 'element-ui/lib/theme-chalk/index.css'
import {Button, Container, Divider, Input, Link, Main, Message} from "element-ui"; import {
Button,
Container,
Divider,
Input,
Link,
Main,
Message,
Select,
Option,
Header,
Form,
FormItem,
Row,
Col,
Notification
} from "element-ui";
import VueLazyload from 'vue-lazyload' import VueLazyload from 'vue-lazyload'
Vue.use(Link); Vue.use(Link);
@ -12,7 +28,15 @@ Vue.use(Button);
Vue.use(Container); Vue.use(Container);
Vue.use(Main); Vue.use(Main);
Vue.use(Divider); Vue.use(Divider);
Vue.use(Select);
Vue.use(Option);
Vue.use(Header);
Vue.use(Form);
Vue.use(FormItem);
Vue.use(Row);
Vue.use(Col);
Vue.prototype.$message = Message; Vue.prototype.$message = Message;
Vue.prototype.$notify = Notification;
Vue.config.productionTip = false; Vue.config.productionTip = false;

@ -6,8 +6,33 @@ const DOMAIN = process.env.base_env.baseShortUrl;
const APIPATH = '/api/v1/fir/server'; const APIPATH = '/api/v1/fir/server';
let USERSEVER = DOMAIN + APIPATH; let USERSEVER = DOMAIN + APIPATH;
function ErrorMsg(error) {
if (error && error.response) {
switch (error.response.status) {
case 400:
error.message = '请求错误(400)';
break;
case 403:
error.message = '拒绝访问(403)';
break;
case 404:
error.message = '请求出错(404)';
break;
case 429:
error.message = '您的 IP 访问频繁,请稍后再次尝试';
break;
default:
error.message = `连接出错(${error.response.status})!`;
}
} else {
error.message = '连接服务器失败!';
}
if (error.message === 'Network Error') {
alert('网络连接失败')
}
}
function getData(url, params = {}, callBack) { function getData(methods = 'GET', url, params = {}, callBack) {
var uri = ''; var uri = '';
@ -25,6 +50,28 @@ function getData(url, params = {}, callBack) {
uri = "?" + uri uri = "?" + uri
} }
url = url + uri; url = url + uri;
if (methods === "PUT") {
Axios
.put(url, params)
.then(function (response) {
callBack(response.data);
})
.catch(function (error) {
ErrorMsg(error);
callBack({"code": -1});
});
} else if (methods === 'POST') {
Axios
.post(url, params)
.then(function (response) {
callBack(response.data);
})
.catch(function (error) {
ErrorMsg(error);
callBack({"code": -1});
});
} else
Axios Axios
.get(url, params) .get(url, params)
.then(function (response) { .then(function (response) {
@ -35,30 +82,7 @@ function getData(url, params = {}, callBack) {
} }
}) })
.catch(function (error) { .catch(function (error) {
ErrorMsg(error);
if (error && error.response) {
switch (error.response.status) {
case 400:
error.message = '请求错误(400)';
break;
case 403:
error.message = '拒绝访问(403)';
break;
case 404:
error.message = '请求出错(404)';
break;
case 429:
error.message = '您的 IP 访问频繁,请稍后再次尝试';
break;
default:
error.message = `连接出错(${error.response.status})!`;
}
} else {
error.message = '连接服务器失败!';
}
if (error.message === 'Network Error') {
alert('网络连接失败')
}
callBack({"code": -1}); callBack({"code": -1});
}); });
} }
@ -67,6 +91,7 @@ function getData(url, params = {}, callBack) {
/**根据短链接获取应用信息 */ /**根据短链接获取应用信息 */
export function getShortAppinfo(callBack, params) { export function getShortAppinfo(callBack, params) {
getData( getData(
'GET',
USERSEVER + '/short/' + params.short, USERSEVER + '/short/' + params.short,
params, params,
data => { data => {
@ -79,6 +104,7 @@ export function getShortAppinfo(callBack, params) {
/**获取下载的url */ /**获取下载的url */
export function getdownloadurl(callBack, params) { export function getdownloadurl(callBack, params) {
getData( getData(
'GET',
USERSEVER + '/install/' + params.app_id, USERSEVER + '/install/' + params.app_id,
params.data, params.data,
data => { data => {
@ -90,6 +116,7 @@ export function getdownloadurl(callBack, params) {
/**获取签名任务状态 */ /**获取签名任务状态 */
export function gettask(callBack, params) { export function gettask(callBack, params) {
getData( getData(
'GET',
USERSEVER + '/task/' + params.short, USERSEVER + '/task/' + params.short,
params.data, params.data,
data => { data => {
@ -97,3 +124,81 @@ export function gettask(callBack, params) {
}, },
); );
} }
/**应用举报 */
export function appReport(callBack, params) {
getData(
params.methods,
USERSEVER + '/report',
params.data,
data => {
callBack(data);
},
);
}
/**token */
export function loginFun(callBack, params) {
getData(
params.methods,
USERSEVER + '/login',
params.data,
data => {
callBack(data);
},
);
}
/**获取验证token */
export function getAuthTokenFun(callBack, params) {
getData(
params.methods,
USERSEVER + '/auth',
params.data,
data => {
callBack(data);
},
);
}
export function checkEmail(email) {
let re = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/;
return re.test(email);
}
export function checkphone(email) {
let re = /^1\d{10}$/;
return re.test(email);
}
export function geetest(self, uid, params, callback) {
loginFun(res => {
if (res.code === 1000) {
let data = res.data;
// eslint-disable-next-line no-undef
initGeetest({
gt: data.gt,
challenge: data.challenge,
new_captcha: data.new_captcha, // 用于宕机时表示是新验证码的宕机
offline: !data.success, // 表示用户后台检测极验服务器是否宕机,一般不需要关注
product: "float", // 产品形式,包括:float,popup
width: "100%"
}, (captchaObj) => {
self.$refs.captcha.innerHTML = '';
captchaObj.appendTo("#captcha");
captchaObj.onReady(() => {
}).onSuccess(() => {
params.geetest = captchaObj.getValidate();
callback(params);
}).onError(() => {
captchaObj.destroy();
});
});
} else {
alert(res.msg);
}
}, {
"methods": "PUT",
"data": {user_id: uid}
});
}

@ -707,3 +707,18 @@ export function DeviceBillInfo(callBack, params, load = true) {
true true
); );
} }
/**应用举报 */
export function appReport(callBack, params, load = true) {
getData(
params.methods,
USERSEVER + '/report',
params.data,
data => {
callBack(data);
},
load,
true,
true
);
}

@ -346,7 +346,7 @@ export function ImgToBase64(url, callback) {
}; };
} }
export function geetest(self, params, callback) { export function geetest(self, uid, params, callback) {
const loading = self.$loading({ const loading = self.$loading({
lock: true, lock: true,
text: 'Loading', text: 'Loading',
@ -385,7 +385,7 @@ export function geetest(self, params, callback) {
} }
}, { }, {
"methods": "PUT", "methods": "PUT",
"data": {user_id: self.form.email} "data": {user_id: uid} //self.form.email
}); });
} }

@ -48,7 +48,7 @@ const mshort = {
// 模板来源 // 模板来源
template: 'public/short.html', template: 'public/short.html',
// 在 dist/short.html 的输出 // 在 dist/short.html 的输出
filename: 'mshort.html', filename: 'short.html',
// 当使用 title 选项时, // 当使用 title 选项时,
// template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title> // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
title: '应用下载', title: '应用下载',
@ -70,7 +70,7 @@ const short = {
// 提取出来的通用 chunk 和 vendor chunk。 // 提取出来的通用 chunk 和 vendor chunk。
chunks: ['chunk-vendors', 'chunk-common', 'short', 'chunk-commons', 'runtime'] chunks: ['chunk-vendors', 'chunk-common', 'short', 'chunk-commons', 'runtime']
}; };
let pages = {index, short}; let pages = {index, short, mshort};
const page = argv[3]; const page = argv[3];
if (page) { if (page) {
for (const key of Object.keys(pages)) { for (const key of Object.keys(pages)) {

@ -29,7 +29,7 @@ class LoginView(APIView):
receive = request.data receive = request.data
username = receive.get("username", None) username = receive.get("username", None)
if LOGIN.get("captcha"): if LOGIN.get("captcha"):
is_valid = valid_captcha(receive.get("cptch_key", None), receive.get("authcode", None), username) is_valid = valid_captcha(receive.get("captcha_key", None), receive.get("authcode", None), username)
else: else:
is_valid = True is_valid = True
if is_valid: if is_valid:

@ -573,6 +573,27 @@ class RemoteClientInfo(models.Model):
return "%s-%s" % (self.remote_addr, self.description) return "%s-%s" % (self.remote_addr, self.description)
class AppReportInfo(models.Model):
app_id = models.ForeignKey(to="Apps", on_delete=models.SET_NULL, verbose_name="应用信息",
null=True, blank=True)
app_name = models.CharField(max_length=32, blank=True, null=True, verbose_name="应用名称")
bundle_id = models.CharField(max_length=64, blank=True, verbose_name="bundle id")
remote_addr = models.GenericIPAddressField(verbose_name="远程IP地址")
report_type_choices = ((0, '侵权'), (1, '色情'), (2, '赌博'), (3, '欺诈'), (4, '暴力'), (5, '其他'),)
report_type = models.SmallIntegerField(choices=report_type_choices, default=5, verbose_name="举报类型")
report_reason = models.CharField(max_length=512, verbose_name="举报详情")
email = models.CharField(max_length=64, verbose_name="联系方式")
username = models.CharField(max_length=64, verbose_name="姓名")
created_time = models.DateTimeField(auto_now_add=True, verbose_name="访问时间")
class Meta:
verbose_name = '应用举报信息'
verbose_name_plural = "应用举报信息"
def __str__(self):
return "%s-%s" % (self.app_name, self.report_reason)
class DeviceQueue(models.Model): class DeviceQueue(models.Model):
app_id = models.ForeignKey(to='Apps', on_delete=models.CASCADE, verbose_name="应用id") app_id = models.ForeignKey(to='Apps', on_delete=models.CASCADE, verbose_name="应用id")
udid = models.CharField(max_length=64, verbose_name="udid唯一标识", db_index=True) udid = models.CharField(max_length=64, verbose_name="udid唯一标识", db_index=True)

@ -24,6 +24,7 @@ from api.views.login import LoginView, UserInfoView, RegistView, AuthorizationVi
from api.views.logout import LogoutView from api.views.logout import LogoutView
from api.views.order import PriceView, OrderView, PaySuccess from api.views.order import PriceView, OrderView, PaySuccess
from api.views.receiveudids import IosUDIDView, TaskView from api.views.receiveudids import IosUDIDView, TaskView
from api.views.report import ReportView
from api.views.storage import StorageView from api.views.storage import StorageView
from api.views.supersign import DeveloperView, SuperSignUsedView, AppUDIDUsedView, SuperSignCertView, DeviceUsedBillView from api.views.supersign import DeveloperView, SuperSignUsedView, AppUDIDUsedView, SuperSignCertView, DeviceUsedBillView
from api.views.thirdlogin import ValidWxChatToken, ThirdWxAccount from api.views.thirdlogin import ValidWxChatToken, ThirdWxAccount
@ -52,6 +53,7 @@ urlpatterns = [
re_path(r"^task/(?P<short>\w+)$", TaskView.as_view()), re_path(r"^task/(?P<short>\w+)$", TaskView.as_view()),
re_path("^analyse$", AppAnalyseView.as_view()), re_path("^analyse$", AppAnalyseView.as_view()),
re_path("^advert$", UserAdInfoView.as_view()), re_path("^advert$", UserAdInfoView.as_view()),
re_path("^report$", ReportView.as_view()),
re_path("^supersign/developer$", DeveloperView.as_view()), re_path("^supersign/developer$", DeveloperView.as_view()),
re_path("^supersign/devices$", SuperSignUsedView.as_view()), re_path("^supersign/devices$", SuperSignUsedView.as_view()),
re_path("^supersign/udid$", AppUDIDUsedView.as_view()), re_path("^supersign/udid$", AppUDIDUsedView.as_view()),

@ -38,11 +38,13 @@ def make_token(release_id, time_limit=60, key='', force_new=False):
return token return token
def verify_token(token, release_id): def verify_token(token, release_id, success_once=False):
try: try:
values = cache.get(token) values = cache.get(token)
if values and release_id == values.get("data", None): if values and release_id == values.get("data", None):
logger.debug(f"verify_token token:{token} release_id:{release_id} success") logger.debug(f"verify_token token:{token} release_id:{release_id} success")
if success_once:
cache.delete(token)
return True return True
except Exception as e: except Exception as e:
logger.error(f"verify_token token:{token} release_id:{release_id} failed Exception:{e}") logger.error(f"verify_token token:{token} release_id:{release_id} failed Exception:{e}")

@ -771,3 +771,9 @@ class BillInfoSerializer(serializers.ModelSerializer):
return f"{obj.user_id.first_name}-{self.get_action(obj)} +{obj.number} 设备数" return f"{obj.user_id.first_name}-{self.get_action(obj)} +{obj.number} 设备数"
else: else:
return f"{obj.to_user_id.first_name} {self.get_action(obj)} -{obj.number} 设备数" return f"{obj.to_user_id.first_name} {self.get_action(obj)} -{obj.number} 设备数"
class AppReportSerializer(serializers.ModelSerializer):
class Meta:
model = models.AppReportInfo
exclude = ["id"]

@ -107,7 +107,7 @@ def get_sender_token(sender, user_id, target, action, msg=None):
code = msg code = msg
token = make_token(code, time_limit=300, key=user_id) token = make_token(code, time_limit=300, key=user_id)
TmpCache.set_tmp_cache(user_id, token, target) TmpCache.set_tmp_cache(user_id, token, target)
if action in ('change', 'password', 'register', 'login'): if action in ('change', 'password', 'register', 'login', 'common'):
sender.send_msg_by_act(target, code, action) sender.send_msg_by_act(target, code, action)
elif action == 'msg': elif action == 'msg':
sender.send_email_msg(target, msg) sender.send_email_msg(target, msg)
@ -124,8 +124,8 @@ def get_sender_sms_token(key, phone, action, msg=None):
return False, False return False, False
def is_valid_sender_code(key, token, code): def is_valid_sender_code(key, token, code, success_once=False):
return verify_token(token, code), TmpCache.get_tmp_cache(key, token) return verify_token(token, code, success_once), TmpCache.get_tmp_cache(key, token)
def get_sender_email_token(key, email, action, msg=None): def get_sender_email_token(key, email, action, msg=None):

@ -5,7 +5,7 @@ from django.core.cache import cache
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
from api.models import Token, UserInfo, UserCertificationInfo, CertificationInfo from api.models import Token, UserInfo, UserCertificationInfo, CertificationInfo, Apps
from api.utils.auth import ExpiringTokenAuthentication from api.utils.auth import ExpiringTokenAuthentication
from api.utils.baseutils import is_valid_phone, is_valid_email, get_real_ip_address from api.utils.baseutils import is_valid_phone, is_valid_email, get_real_ip_address
from api.utils.geetest.geetest_utils import first_register, second_validate from api.utils.geetest.geetest_utils import first_register, second_validate
@ -18,7 +18,7 @@ from api.utils.throttle import VisitRegister1Throttle, VisitRegister2Throttle, G
from api.utils.utils import get_captcha, valid_captcha, \ from api.utils.utils import get_captcha, valid_captcha, \
get_sender_sms_token, is_valid_sender_code, get_sender_email_token, get_random_username, \ get_sender_sms_token, is_valid_sender_code, get_sender_email_token, get_random_username, \
check_username_exists, set_user_token check_username_exists, set_user_token
from fir_ser.settings import REGISTER, LOGIN, CHANGER from fir_ser.settings import REGISTER, LOGIN, CHANGER, REPORT
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -203,6 +203,49 @@ def check_change_userinfo(target, act, key, user, ftype=None):
return res return res
def check_common_info(target, act):
res = BaseResponse()
res.data = {}
times_key = "%s_%s_%s" % ('report', act, target)
if act == "sms":
if is_valid_phone(target):
if login_auth_failed("get", times_key):
login_auth_failed("set", times_key)
token, code = get_sender_sms_token(act, target, 'common')
if token:
res.data["auth_token"] = token
else:
res.code = 1009
res.msg = "短信服务异常,请联系管理员"
else:
res.code = 1009
res.msg = "该手机号今日使用次数已经达到上限"
else:
res.code = 1005
res.msg = "手机号校验失败"
elif act == "email":
if is_valid_email(target):
if login_auth_failed("get", times_key):
login_auth_failed("set", times_key)
token, code = get_sender_email_token(act, target, 'common')
if token:
res.data["auth_token"] = token
else:
res.code = 1009
res.msg = "邮件服务异常,请联系管理员"
else:
res.code = 1009
res.msg = "该邮箱今日使用次数已经达到上限"
else:
res.code = 1006
res.msg = "邮箱校验失败"
else:
res.code = 1007
res.msg = "信息发送失败"
return res
class LoginView(APIView): class LoginView(APIView):
throttle_classes = [VisitRegister1Throttle, VisitRegister2Throttle] throttle_classes = [VisitRegister1Throttle, VisitRegister2Throttle]
@ -211,7 +254,7 @@ class LoginView(APIView):
receive = request.data receive = request.data
username = receive.get("username", None) username = receive.get("username", None)
if LOGIN.get("captcha"): if LOGIN.get("captcha"):
is_valid = valid_captcha(receive.get("cptch_key", None), receive.get("authcode", None), username) is_valid = valid_captcha(receive.get("captcha_key", None), receive.get("authcode", None), username)
else: else:
is_valid = True is_valid = True
if is_valid: if is_valid:
@ -466,7 +509,7 @@ class UserInfoView(APIView):
email = data.get("email", None) email = data.get("email", None)
if mobile or email: if mobile or email:
if CHANGER.get('captcha'): if CHANGER.get('captcha'):
is_valid = valid_captcha(data.get("cptch_key", None), data.get("authcode", None), request) is_valid = valid_captcha(data.get("captcha_key", None), data.get("authcode", None), request)
if not is_valid: if not is_valid:
res.code = 1008 res.code = 1008
res.msg = "图片验证码异常" res.msg = "图片验证码异常"
@ -578,8 +621,11 @@ class AuthorizationView(APIView):
res.msg = "邀请码已失效" res.msg = "邀请码已失效"
return Response(res.dict) return Response(res.dict)
if ext and ext.get('report'):
REGISTER = REPORT
if REGISTER.get("captcha"): if REGISTER.get("captcha"):
is_valid = valid_captcha(ext.get("cptch_key", None), ext.get("authcode", None), target) is_valid = valid_captcha(ext.get("captcha_key", None), ext.get("authcode", None), target)
if ext and is_valid: if ext and is_valid:
pass pass
else: else:
@ -595,6 +641,14 @@ class AuthorizationView(APIView):
res.code = 1018 res.code = 1018
res.msg = "geetest验证有误" res.msg = "geetest验证有误"
return Response(res.dict) return Response(res.dict)
if ext and ext.get('report'):
app_obj = Apps.objects.filter(app_id=ext.get('report')).first()
if app_obj:
res = check_common_info(target, act)
else:
res.code = 1003
res.msg = '未授权,请重新提交'
return Response(res.dict)
res = check_register_userinfo(target, act, 'register') res = check_register_userinfo(target, act, 'register')
@ -613,7 +667,7 @@ class ChangeAuthorizationView(APIView):
ext = request.data.get("ext", None) ext = request.data.get("ext", None)
f_type = request.data.get("ftype", None) f_type = request.data.get("ftype", None)
if REGISTER.get("captcha"): if REGISTER.get("captcha"):
if ext and valid_captcha(ext.get("cptch_key", None), ext.get("authcode", None), target): if ext and valid_captcha(ext.get("captcha_key", None), ext.get("authcode", None), target):
pass pass
else: else:
res.code = 1009 res.code = 1009
@ -701,8 +755,9 @@ class CertificationView(APIView):
try: try:
if CHANGER.get("captcha"): if CHANGER.get("captcha"):
if data and valid_captcha(data.get("cptch_key", None), data.get("authcode", None), data.get("mobile")): if data and valid_captcha(data.get("captcha_key", None), data.get("authcode", None),
del data["cptch_key"] data.get("mobile")):
del data["captcha_key"]
del data["authcode"] del data["authcode"]
else: else:
res.code = 1009 res.code = 1009

@ -0,0 +1,76 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 11月
# author: NinEveN
# date: 2021/11/4
import logging
from rest_framework.response import Response
from rest_framework.views import APIView
from api.models import Apps, AppReportInfo
from api.utils.baseutils import get_real_ip_address
from api.utils.modelutils import add_remote_info_from_request
from api.utils.response import BaseResponse
from api.utils.serializer import AppReportSerializer
from api.utils.storage.caches import login_auth_failed
from api.utils.throttle import InstallThrottle2
from api.utils.utils import is_valid_sender_code, get_captcha, get_choices_dict
from fir_ser.settings import REPORT
logger = logging.getLogger(__name__)
class ReportView(APIView):
throttle_classes = [InstallThrottle2]
def get(self, request):
response = BaseResponse()
response.data = {}
allow_f = REPORT.get("enable")
if allow_f:
if REPORT.get("captcha"):
response.data = get_captcha()
if REPORT.get("geetest"):
response.data['geetest'] = True
response.data['report_type'] = REPORT.get("report_type")
response.data['s_list'] = get_choices_dict(AppReportInfo.report_type_choices)
response.data['enable'] = allow_f
return Response(response.dict)
def post(self, request):
res = BaseResponse()
data = request.data
msg = f"add new app report data:{data}"
logger.info(msg)
email = data.get('email', '')
is_valid, target = is_valid_sender_code(data.get('act'), data.get("auth_token", None),
data.get("seicode", None), True)
if is_valid and str(target) == str(email):
if login_auth_failed("get", email):
add_remote_info_from_request(request, msg)
if data.get('app_id'):
app_obj = Apps.objects.filter(app_id=data.get('app_id')).first()
ext_info = {
'app_name': app_obj.name,
'bundle_id': app_obj.bundle_id,
'remote_addr': get_real_ip_address(request),
'app_id': app_obj.pk
}
data.update(ext_info)
serializer = AppReportSerializer(data=data, context={'user_obj': request.user})
if serializer.is_valid():
serializer.save()
else:
logger.info(f"add new app report failed")
res.msg = serializer.errors
res.code = 1005
else:
res.code = 1006
logger.error("email:%s failed too try , locked" % (email,))
res.msg = "失败次数过多,已被锁定,请1小时之后再次尝试"
else:
res.code = 1001
res.msg = "验证码有误或失效"
return Response(res.dict)

@ -126,6 +126,15 @@ class AUTHCONF(object):
}, },
} }
} }
REPORT = {
"enable": True,
"captcha": True, # 是否开启注册字母验证码
"geetest": False, # 是否开启geetest验证,如要开启请先配置geetest
"report_type": {
'sms': False, # 短信举报
'email': True, # 邮件举报
}
}
class STORAGEKEYCONF(object): class STORAGEKEYCONF(object):
@ -186,13 +195,14 @@ class SENDERCONF(object):
'use_ssl': True, 'use_ssl': True,
'username': 'flyapps@126.com', 'username': 'flyapps@126.com',
'password': 'GGHFEUMZBRZIFZGQ', 'password': 'GGHFEUMZBRZIFZGQ',
'form': 'FlyApp Validation <flyapps@126.com>', 'form': 'fly分发平台 <flyapps@126.com>',
'subject': '%(code)s验证', 'subject': '%(code)s验证',
'template_code': { 'template_code': {
'login': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s ,您正在登录,若非本人操作,请勿泄露。', 'login': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s ,您正在登录,若非本人操作,请勿泄露。',
'change': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s ,您正在尝试变更重要信息,请妥善保管账户信息。', 'change': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s ,您正在尝试变更重要信息,请妥善保管账户信息。',
'register': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s ,您正在注册成为新用户,感谢您的支持!', 'register': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s ,您正在注册成为新用户,感谢您的支持!',
'password': '欢迎使用FLY 应用分发平台。 您的新密码为%(code)s , 请用新密码登录之后,及时修改密码,并妥善保管账户信息。' 'password': '欢迎使用FLY 应用分发平台。 您的新密码为%(code)s , 请用新密码登录之后,及时修改密码,并妥善保管账户信息。',
'common': '欢迎使用FLY 应用分发平台。 您的验证码%(code)s , 若非本人操作,请忽略。'
} }
}, },
'active': True 'active': True
@ -209,7 +219,8 @@ class SENDERCONF(object):
'login': 'SMS_216700569', 'login': 'SMS_216700569',
'change': 'SMS_216700566', 'change': 'SMS_216700566',
'register': 'SMS_216700567', 'register': 'SMS_216700567',
'password': 'SMS_222341718' 'password': 'SMS_222341718',
'common': 'SMS_227259072'
} }
}, },
'active': True 'active': True
@ -225,7 +236,8 @@ class SENDERCONF(object):
'login': '1', 'login': '1',
'change': '1', 'change': '1',
'register': '1', 'register': '1',
'password': '1' 'password': '1',
'common': '1',
} }
}, },
'active': False 'active': False

@ -192,7 +192,7 @@ REGISTER = AUTHCONF.REGISTER
# 个人资料修改修改也会使用该配置 # 个人资料修改修改也会使用该配置
CHANGER = AUTHCONF.CHANGER CHANGER = AUTHCONF.CHANGER
LOGIN = AUTHCONF.LOGIN LOGIN = AUTHCONF.LOGIN
REPORT = AUTHCONF.REPORT
THIRD_PART_CONFIG_KEY_INFO = { THIRD_PART_CONFIG_KEY_INFO = {
# APP存储配置 # APP存储配置
'storage_key': STORAGEKEYCONF.STORAGE, 'storage_key': STORAGEKEYCONF.STORAGE,

Loading…
Cancel
Save