优化代码

dependabot/npm_and_yarn/fir_admin/url-parse-1.5.10
MMXX 3 years ago
parent c361d740bf
commit 59d7d905d3
  1. 3
      fir_client/src/components/FirBase.vue
  2. 2
      fir_client/src/components/apps/FirAppInfosBase.vue
  3. 4
      fir_client/src/components/apps/FirAppInfossecurity.vue
  4. 2
      fir_client/src/components/apps/FirApps.vue
  5. 13
      fir_client/src/components/base/BindDomain.vue
  6. 107
      fir_client/src/components/user/FirSuperSignBase.vue
  7. 2
      fir_client/src/components/user/FirUserAdvert.vue
  8. 32
      fir_client/src/components/user/FirUserDomain.vue
  9. 17
      fir_client/src/components/user/FirUserOrders.vue
  10. 4
      fir_client/src/components/user/FirUserQrcode.vue
  11. 8
      fir_client/src/utils/index.js
  12. 13
      fir_ser/api/migrations/0028_auto_20211228_1454.py
  13. 5
      fir_ser/api/models.py
  14. 33
      fir_ser/api/utils/app/iossignapi.py
  15. 141
      fir_ser/api/utils/app/supersignutils.py
  16. 3
      fir_ser/api/utils/apple/appleapiv3.py
  17. 14
      fir_ser/api/utils/crontab/ctasks.py
  18. 3
      fir_ser/api/utils/serializer.py
  19. 4
      fir_ser/api/utils/utils.py
  20. 34
      fir_ser/api/views/supersign.py

@ -125,7 +125,8 @@ export default {
font-size: medium; font-size: medium;
margin-right: 20px; margin-right: 20px;
} }
/deep/ .el-alert{
/deep/ .el-alert {
padding: 2px 16px; padding: 2px 16px;
} }
</style> </style>

@ -150,7 +150,7 @@ export default {
a.dispatchEvent(new MouseEvent('click')) a.dispatchEvent(new MouseEvent('click'))
}, },
short_url(appinfo) { short_url(appinfo) {
return appinfo.preview_url+ '/' + appinfo.short; return appinfo.preview_url + '/' + appinfo.short;
}, },
setfunactive(item, index) { setfunactive(item, index) {
for (let key in this.$refs) { for (let key in this.$refs) {

@ -6,8 +6,8 @@
:visible.sync="bind_domain_sure" :visible.sync="bind_domain_sure"
title="绑定应用专属下载页域名" title="绑定应用专属下载页域名"
width="666px"> width="666px">
<bind-domain v-if="bind_domain_sure" :app_id="this.currentapp.app_id" :domain_type="2" <bind-domain v-if="bind_domain_sure" :app_id="this.currentapp.app_id" :c_domain_name="this.currentapp.domain_name"
:c_domain_name="this.currentapp.domain_name" transitionName="bind-app-domain"/> :domain_type="2" transitionName="bind-app-domain"/>
</el-dialog> </el-dialog>
<el-form label-width="80px"> <el-form label-width="80px">
<el-form-item label="访问密码" label-width="200px"> <el-form-item label="访问密码" label-width="200px">

@ -1140,7 +1140,7 @@ export default {
this.$router.push({name: 'FirAppInfostimeline', params: {id: app.app_id}}) this.$router.push({name: 'FirAppInfostimeline', params: {id: app.app_id}})
}, },
appDownload(app) { appDownload(app) {
window.open(app.preview_url+ '/' + app.short, '_blank', ''); window.open(app.preview_url + '/' + app.short, '_blank', '');
} }
}, computed: { }, computed: {
getDelappTitle() { getDelappTitle() {

@ -181,7 +181,7 @@ export default {
bind_status: false, bind_status: false,
bind_domain_sure: true, bind_domain_sure: true,
domain_tData: [{'type': 'CNAME', 'host': 'xxx', 'dns': 'demo.xxx.cn'}], domain_tData: [{'type': 'CNAME', 'host': 'xxx', 'dns': 'demo.xxx.cn'}],
domain_name:'', domain_name: '',
force_bind: false, force_bind: false,
b_t_msg: '您的账户', b_t_msg: '您的账户',
} }
@ -190,7 +190,7 @@ export default {
if (this.domain_type === 2) { if (this.domain_type === 2) {
this.b_t_msg = '您的应用' this.b_t_msg = '您的应用'
} }
if(this.c_domain_name){ if (this.c_domain_name) {
this.domain_name = this.c_domain_name this.domain_name = this.c_domain_name
} }
this.bind_click(); this.bind_click();
@ -225,7 +225,7 @@ export default {
this.bind_status = false; this.bind_status = false;
this.$message.error("绑定失败 " + data.msg) this.$message.error("绑定失败 " + data.msg)
} }
}, {methods: 'PUT', data: {app_id: this.app_id, domain_type: this.domain_type, domain_name:this.domain_name}}) }, {methods: 'PUT', data: {app_id: this.app_id, domain_type: this.domain_type, domain_name: this.domain_name}})
}, },
remove_domain() { remove_domain() {
domainFun(data => { domainFun(data => {
@ -244,7 +244,10 @@ export default {
} else { } else {
this.$message.error("解除绑定失败 " + data.msg) this.$message.error("解除绑定失败 " + data.msg)
} }
}, {methods: 'DELETE', data: {app_id: this.app_id, domain_type: this.domain_type, domain_name:this.domain_name}}); }, {
methods: 'DELETE',
data: {app_id: this.app_id, domain_type: this.domain_type, domain_name: this.domain_name}
});
}, },
bind_click() { bind_click() {
this.$store.dispatch("dosetdomainstate", false); this.$store.dispatch("dosetdomainstate", false);
@ -267,7 +270,7 @@ export default {
} else { } else {
this.$message.error("绑定失败 " + data.msg) this.$message.error("绑定失败 " + data.msg)
} }
}, {methods: 'GET', data: {app_id: this.app_id, domain_type: this.domain_type, domain_name:this.domain_name}}); }, {methods: 'GET', data: {app_id: this.app_id, domain_type: this.domain_type, domain_name: this.domain_name}});
}, },
format_domain_tData(cname_domain) { format_domain_tData(cname_domain) {
let domain_name_list = this.domain_name.split('.'); let domain_name_list = this.domain_name.split('.');

@ -67,6 +67,18 @@
{{ editdeveloperinfo.app_used_count }} 个应用 {{ editdeveloperinfo.app_used_count }} 个应用
</el-tag> </el-tag>
</el-form-item> </el-form-item>
<el-form-item label="维护模式" label-width="110px" style="text-align: left">
<el-switch
v-model="read_only_mode"
:disabled="read_only_mode==='on'"
active-color="#13ce66"
active-value="on"
inactive-color="#ff4949"
inactive-value="off">
</el-switch>
<el-tag style="margin-left: 10px" type="warning"> 该模式下新设备新应用无法进行注册安装但是已经安装的不影响</el-tag>
<el-tag v-if="read_only_mode==='on'" style="margin-left: 50px" type="warning"> 通过账户激活进行关闭维护模式</el-tag>
</el-form-item>
<el-form-item label="证书id" label-width="110px"> <el-form-item label="证书id" label-width="110px">
<el-input v-model="editdeveloperinfo.certid" :disabled='isedit'/> <el-input v-model="editdeveloperinfo.certid" :disabled='isedit'/>
</el-form-item> </el-form-item>
@ -84,7 +96,7 @@
type="danger" type="danger"
@click="cleandevices">清理签名数据 @click="cleandevices">清理签名数据
</el-button> </el-button>
<el-button v-if="isedit && editdeveloperinfo.is_actived || editdeveloperinfo.certid" size="small" <el-button v-if="isedit && editdeveloperinfo.status!==0 || editdeveloperinfo.certid" size="small"
@click="syncdevices">同步设备信息 @click="syncdevices">同步设备信息
</el-button> </el-button>
<el-tooltip content="发布证书只能创建两个,请谨慎操作"> <el-tooltip content="发布证书只能创建两个,请谨慎操作">
@ -100,7 +112,7 @@
@click="isorenewcert">删除发布证书 @click="isorenewcert">删除发布证书
</el-button> </el-button>
</el-tooltip> </el-tooltip>
<el-button v-if="isedit && editdeveloperinfo.is_actived" size="small" type="success" <el-button v-if="isedit && editdeveloperinfo.status!==0" size="small" type="success"
@click="activedeveloperFun(editdeveloperinfo,'checkauth')">账户激活检测 @click="activedeveloperFun(editdeveloperinfo,'checkauth')">账户激活检测
</el-button> </el-button>
<!-- <el-button v-if="isedit && editdeveloperinfo.is_actived" size="small" @click="bindAppletoapp(editdeveloperinfo)">专属应用</el-button>--> <!-- <el-button v-if="isedit && editdeveloperinfo.is_actived" size="small" @click="bindAppletoapp(editdeveloperinfo)">专属应用</el-button>-->
@ -268,10 +280,10 @@
<el-table-column <el-table-column
align="center" align="center"
label="是否激活" label="是否激活"
prop="is_actived" prop="status"
width="110"> width="110">
<template slot-scope="scope"> <template slot-scope="scope">
<el-tooltip v-if="scope.row.is_actived === true" content="点击禁用"> <el-tooltip v-if="scope.row.status!==0" content="点击禁用">
<el-button size="small" type="success" @click="disabledeveloperFun(scope.row,'disable')">已激活</el-button> <el-button size="small" type="success" @click="disabledeveloperFun(scope.row,'disable')">已激活</el-button>
</el-tooltip> </el-tooltip>
<el-button v-else size="small" type="danger" <el-button v-else size="small" type="danger"
@ -284,15 +296,24 @@
align="center" align="center"
label="账户状态" label="账户状态"
prop="certid" prop="certid"
width="100"> sortable
width="110">
<template slot-scope="scope"> <template slot-scope="scope">
<el-popover placement="top" trigger="hover"> <el-popover placement="top" trigger="hover">
<p v-if="!scope.row.certid && scope.row.is_actived === true"> <p v-if="!scope.row.certid && scope.row.status!==0">
开发证书不可用请在编辑中导入或手动创建发布证书</p> 开发证书不可用请在编辑中导入或手动创建发布证书</p>
<p v-if="!scope.row.certid && scope.row.is_actived !== true">请先激活开发者账户</p> <p v-if="!scope.row.certid && scope.row.status=== 0">请先激活开发者账户</p>
<p v-if="scope.row.certid && scope.row.is_actived === true">账户已经启用</p> <p v-if="scope.row.certid && scope.row.status!==0">{{ format_status(scope.row) }}</p>
<div slot="reference" class="name-wrapper"> <div slot="reference" class="name-wrapper">
<el-button v-if="scope.row.certid " size="small" type="success">可用</el-button> <div v-if="scope.row.certid">
<el-button v-if="scope.row.status === 1" size="small" type="success">
{{ format_status(scope.row) }}
</el-button>
<el-button v-else size="small" type="warning" @click="activedeveloperFun(scope.row,'checkauth')">
{{ format_status(scope.row) }}
</el-button>
</div>
<el-button v-else size="small" type="danger">不可用</el-button> <el-button v-else size="small" type="danger">不可用</el-button>
</div> </div>
</el-popover> </el-popover>
@ -300,22 +321,17 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
:formatter="formatter_usable_number"
align="center" align="center"
label="可用设备" label="可用设备"
prop="usable_number" prop="usable_number"
width="60"> sortable
width="70">
<template slot-scope="scope"> <template slot-scope="scope">
<el-popover placement="top" trigger="hover"> <el-popover placement="top" trigger="hover">
<p>可用设备数: {{ <p>可用设备数: {{ formatter_usable_number(scope.row) }}</p>
scope.row.usable_number - scope.row.developer_used_number > 0
? scope.row.usable_number - scope.row.developer_used_number : 0
}}</p>
<div slot="reference" class="name-wrapper"> <div slot="reference" class="name-wrapper">
<el-tag size="medium"> {{ <el-tag size="medium"> {{ formatter_usable_number(scope.row) }}</el-tag>
scope.row.usable_number - scope.row.developer_used_number >
0 ? scope.row.usable_number - scope.row.developer_used_number : 0
}}
</el-tag>
</div> </div>
</el-popover> </el-popover>
</template> </template>
@ -946,7 +962,7 @@ import {
iosdevicesudid, iosdevicesudid,
iosudevices iosudevices
} from "@/restful"; } from "@/restful";
import {getUserInfoFun, removeAaary} from "@/utils"; import {format_choices, getUserInfoFun, removeAaary} from "@/utils";
import AppleDeveloperBindApp from "@/components/base/AppleDeveloperBindApp"; import AppleDeveloperBindApp from "@/components/base/AppleDeveloperBindApp";
export default { export default {
@ -1033,7 +1049,9 @@ export default {
], ],
developer_choice: '', developer_choice: '',
bind_appletoapp_sure: false, bind_appletoapp_sure: false,
appletoapp_title: '' appletoapp_title: '',
status_choices: [],
read_only_mode: 'off'
} }
}, watch: { }, watch: {
'dialogaddDeveloperVisible': function () { 'dialogaddDeveloperVisible': function () {
@ -1043,6 +1061,12 @@ export default {
} }
}, },
methods: { methods: {
formatter_usable_number(row) {
return row.usable_number - row.developer_used_number > 0 ? row.usable_number - row.developer_used_number : 0
},
format_status(row) {
return format_choices(row.status, this.status_choices)
},
downloadipa(info) { downloadipa(info) {
this.loading = true; this.loading = true;
iosdevices(data => { iosdevices(data => {
@ -1268,9 +1292,15 @@ export default {
this.dialogaddDeveloperVisible = true; this.dialogaddDeveloperVisible = true;
this.isedit = true; this.isedit = true;
this.placeholder = "为空表示不修改该信息" this.placeholder = "为空表示不修改该信息"
if (this.editdeveloperinfo.status === 3) {
this.read_only_mode = 'on'
} else {
this.read_only_mode = 'off'
}
}, },
updateorcreate() { updateorcreate() {
if (this.isedit) { if (this.isedit) {
this.editdeveloperinfo.read_only_mode = this.read_only_mode
this.iosdeveloperFun({"methods": "PUT", "data": this.editdeveloperinfo}) this.iosdeveloperFun({"methods": "PUT", "data": this.editdeveloperinfo})
} else { } else {
if (this.editdeveloperinfo.auth_type === 0) { if (this.editdeveloperinfo.auth_type === 0) {
@ -1385,19 +1415,26 @@ export default {
} else { } else {
this.loading = true this.loading = true
} }
if (params.methods === 'PUT') {
params.data.size = this.pagination.pagesize
params.data.page = this.pagination.currentPage
}
iosdeveloper(data => { iosdeveloper(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.app_developer_lists = data.data; if (params.methods !== 'PUT') {
this.pagination.total = data.count; this.app_developer_lists = data.data;
this.apple_auth_list = data.apple_auth_list; this.pagination.total = data.count;
if (data.use_num) { this.apple_auth_list = data.apple_auth_list;
this.developer_used_info = data.use_num; this.status_choices = data.status_choices;
if (this.developer_used_info.all_usable_number !== 0) { if (data.use_num) {
let p = parseInt((this.developer_used_info.flyapp_used_sum + this.developer_used_info.other_used_sum) * 100 / this.developer_used_info.all_usable_number); this.developer_used_info = data.use_num;
if (p < 0 || p >= 100) { if (this.developer_used_info.all_usable_number !== 0) {
p = 100 let p = parseInt((this.developer_used_info.flyapp_used_sum + this.developer_used_info.other_used_sum) * 100 / this.developer_used_info.all_usable_number);
if (p < 0 || p >= 100) {
p = 100
}
this.percentage = p;
} }
this.percentage = p;
} }
} }
@ -1407,7 +1444,7 @@ export default {
this.activeName = "iosdeveloper"; this.activeName = "iosdeveloper";
this.editdeveloperinfo = {auth_type: 0, usable_number: 100, app_limit_number: 100}; this.editdeveloperinfo = {auth_type: 0, usable_number: 100, app_limit_number: 100};
} }
if (!this.edit && this.editdeveloperinfo.issuer_id) { if (params.methods === 'POST') {
this.$message.success("添加成功"); this.$message.success("添加成功");
this.activeName = "iosdeveloper"; this.activeName = "iosdeveloper";
this.editdeveloperinfo = {auth_type: 0, usable_number: 100, app_limit_number: 100}; this.editdeveloperinfo = {auth_type: 0, usable_number: 100, app_limit_number: 100};
@ -1417,6 +1454,12 @@ export default {
} else { } else {
this.$message.error("操作失败") this.$message.error("操作失败")
} }
if (params.methods === 'PUT') {
this.get_data_from_tabname(this.activeName, {
"size": this.pagination.pagesize,
"page": this.pagination.currentPage
})
}
if (params.methods !== 'GET') { if (params.methods !== 'GET') {
this.loadingfun.close(); this.loadingfun.close();
} else { } else {

@ -54,7 +54,7 @@
action="#" action="#"
drag drag
style="max-height: 200px"> style="max-height: 200px">
<img v-if="upload_pic_b" :src="upload_pic_b" class="avatar" alt=""> <img v-if="upload_pic_b" :src="upload_pic_b" alt="" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i> <i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload> </el-upload>
</el-form-item> </el-form-item>

@ -6,8 +6,10 @@
:title="domain_title" :title="domain_title"
:visible.sync="bind_domain_sure" :visible.sync="bind_domain_sure"
width="666px"> width="666px">
<bind-domain v-if="bind_domain_sure" :app_id="current_domain_info.app_id" :domain_state="true" <bind-domain v-if="bind_domain_sure" :app_id="current_domain_info.app_id"
:domain_type="current_domain_info.domain_type" :c_domain_name="current_domain_info.domain_name" transitionName="bind-app-domain"/> :c_domain_name="current_domain_info.domain_name"
:domain_state="true" :domain_type="current_domain_info.domain_type"
transitionName="bind-app-domain"/>
</el-dialog> </el-dialog>
<div> <div>
<el-input <el-input
@ -25,7 +27,7 @@
</el-button> </el-button>
</el-tooltip> </el-tooltip>
<el-tooltip content="用与生成预览和下载码的域名"> <el-tooltip content="用与生成预览和下载码的域名">
<el-button plain type="primary" @click="$store.dispatch('dodomainaction', 2)"> <el-button plain type="primary" @click="$store.dispatch('dodomainaction', 2)">
设置下载码域名 设置下载码域名
</el-button> </el-button>
</el-tooltip> </el-tooltip>
@ -106,18 +108,18 @@
prop="weight" prop="weight"
width="110"> width="110">
<template slot-scope="scope"> <template slot-scope="scope">
<el-popover placement="top" trigger="hover" v-if="scope.row.domain_type === 1"> <el-popover v-if="scope.row.domain_type === 1" placement="top" trigger="hover">
<p>绑定域名{{ scope.row.domain_name }}</p> <p>绑定域名{{ scope.row.domain_name }}</p>
<p>域名类型{{format_domain_type(scope.row)}}</p> <p>域名类型{{ format_domain_type(scope.row) }}</p>
<p>权重越大下载域名使用频率越高</p> <p>权重越大下载域名使用频率越高</p>
<p > <p>
跳转权重: 跳转权重:
<el-input-number v-model="scope.row.weight" :max="100" :min="1" <el-input-number v-model="scope.row.weight" :max="100" :min="1"
label="跳转权重" size="small"/> label="跳转权重" size="small"/>
<el-button size="small" style="margin-left: 10px" @click="saveWeight(scope.row)">保存修改</el-button> <el-button size="small" style="margin-left: 10px" @click="saveWeight(scope.row)">保存修改</el-button>
</p> </p>
<div slot="reference" class="name-wrapper"> <div slot="reference" class="name-wrapper">
<el-link :underline="false" plain size="small">{{ scope.row.weight}} <el-link :underline="false" plain size="small">{{ scope.row.weight }}
</el-link> </el-link>
</div> </div>
@ -154,7 +156,7 @@
import {domaininfo} from "@/restful"; import {domaininfo} from "@/restful";
import BindDomain from "@/components/base/BindDomain"; import BindDomain from "@/components/base/BindDomain";
import {getUserInfoFun} from '@/utils' import {format_choices, getUserInfoFun} from '@/utils'
export default { export default {
name: "FirUserDomain", name: "FirUserDomain",
@ -172,13 +174,13 @@ export default {
} }
}, },
methods: { methods: {
saveWeight(domain_info){ saveWeight(domain_info) {
domaininfo(data => { domaininfo(data => {
if (data.code === 1000) { if (data.code === 1000) {
this.$message.success("权重修改成功") this.$message.success("权重修改成功")
} else { } else {
this.$message.error("权重修改失败 "+data.msg) this.$message.error("权重修改失败 " + data.msg)
} }
}, {methods: 'PUT', data: domain_info}) }, {methods: 'PUT', data: domain_info})
}, },
@ -234,20 +236,12 @@ export default {
this.loading = false; this.loading = false;
}, {methods: 'GET', data: params}) }, {methods: 'GET', data: params})
}, },
format_choices(key, obj) {
for (let i = 0; i < obj.length; i++) {
if (key === obj[i].id) {
return obj[i].name
}
}
return "未知"
},
format_domain_type(row) { format_domain_type(row) {
if (row.domain_type === 2) { if (row.domain_type === 2) {
return "应用" + row.app_info.name + "域名" return "应用" + row.app_info.name + "域名"
} }
return this.format_choices(row.domain_type, this.domain_type_choices) return format_choices(row.domain_type, this.domain_type_choices)
}, },
format_create_time(row) { format_create_time(row) {

@ -248,7 +248,7 @@
<script> <script>
import {my_order} from "@/restful"; import {my_order} from "@/restful";
import {getUserInfoFun} from '@/utils' import {format_choices, getUserInfoFun} from '@/utils'
import VueQr from 'vue-qr'; import VueQr from 'vue-qr';
export default { export default {
@ -364,25 +364,16 @@ export default {
this.MyOrderFun(data) this.MyOrderFun(data)
}, },
format_choices(key, obj) {
for (let i = 0; i < obj.length; i++) {
if (key === obj[i].id) {
return obj[i].name
}
}
return "未知"
},
format_payment_type(row) { format_payment_type(row) {
return this.format_choices(row.payment_type, this.payment_type_choices) return format_choices(row.payment_type, this.payment_type_choices)
}, },
format_status_type(row) { format_status_type(row) {
return this.format_choices(row.status, this.status_choices) return format_choices(row.status, this.status_choices)
}, },
format_order_type(row) { format_order_type(row) {
return this.format_choices(row.order_type, this.order_type_choices) return format_choices(row.order_type, this.order_type_choices)
}, },
format_actual_amount(row) { format_actual_amount(row) {

@ -64,7 +64,7 @@
&nbsp; &nbsp;
<span>{{ appinfo.name }}</span> <span>{{ appinfo.name }}</span>
<div class="bottom clearfix"> <div class="bottom clearfix">
<el-popover placement="top" trigger="hover" > <el-popover placement="top" trigger="hover">
<span v-clipboard:copy="short_url(appinfo)" <span v-clipboard:copy="short_url(appinfo)"
v-clipboard:success="copy_success" v-clipboard:success="copy_success"
>{{ short_url(appinfo) }}</span> >{{ short_url(appinfo) }}</span>
@ -220,7 +220,7 @@ export default {
this.allQrcodeAppid.push(id); this.allQrcodeAppid.push(id);
}, },
short_url(appinfo) { short_url(appinfo) {
return appinfo.preview_url+ '/' + appinfo.short; return appinfo.preview_url + '/' + appinfo.short;
}, },
save_qr(appinfo) { save_qr(appinfo) {
let dtype = "I"; let dtype = "I";

@ -688,3 +688,11 @@ export function sort_compare(propertyName) {
} }
} }
export function format_choices(key, obj) {
for (let i = 0; i < obj.length; i++) {
if (key === obj[i].id) {
return obj[i].name
}
}
return "未知"
}

@ -1,4 +1,4 @@
# Generated by Django 3.2.3 on 2021-12-20 17:11 # Generated by Django 3.2.3 on 2021-12-28 14:54
from django.db import migrations, models from django.db import migrations, models
@ -9,6 +9,17 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RemoveField(
model_name='appiosdeveloperinfo',
name='is_actived',
),
migrations.AddField(
model_name='appiosdeveloperinfo',
name='status',
field=models.SmallIntegerField(
choices=[(0, '未激活'), (1, '已激活'), (2, '协议待同意'), (3, '维护中'), (4, '证书过期'), (5, '状态异常')], default=0,
verbose_name='账户状态'),
),
migrations.AddField( migrations.AddField(
model_name='userdomaininfo', model_name='userdomaininfo',
name='is_https', name='is_https',

@ -270,7 +270,7 @@ class AppIOSDeveloperInfo(models.Model):
private_key_id = models.CharField(max_length=64, null=False, verbose_name="密钥 ID") private_key_id = models.CharField(max_length=64, null=False, verbose_name="密钥 ID")
# p8key = models.TextField(max_length=512, null=False, verbose_name="p8key") # p8key = models.TextField(max_length=512, null=False, verbose_name="p8key")
p8key = AESCharField(max_length=512, null=False, verbose_name="p8key") p8key = AESCharField(max_length=512, null=False, verbose_name="p8key")
is_actived = models.BooleanField(default=False, verbose_name="是否已经激活") # is_actived = models.BooleanField(default=False, verbose_name="是否已经激活")
certid = models.CharField(max_length=64, blank=True, verbose_name="超级签名自动创建证书ID", null=True) certid = models.CharField(max_length=64, blank=True, verbose_name="超级签名自动创建证书ID", null=True)
usable_number = models.IntegerField(verbose_name="可使用设备数", default=100) usable_number = models.IntegerField(verbose_name="可使用设备数", default=100)
app_limit_number = models.IntegerField(verbose_name="可分配应用数,最大160", default=100) app_limit_number = models.IntegerField(verbose_name="可分配应用数,最大160", default=100)
@ -280,6 +280,9 @@ class AppIOSDeveloperInfo(models.Model):
description = models.TextField('备注', blank=True, null=True, default='') description = models.TextField('备注', blank=True, null=True, default='')
auth_type_choices = ((0, 'p8key认证'),) auth_type_choices = ((0, 'p8key认证'),)
auth_type = models.SmallIntegerField(choices=auth_type_choices, default=0, verbose_name="认证类型") auth_type = models.SmallIntegerField(choices=auth_type_choices, default=0, verbose_name="认证类型")
status_choices = (
(0, '未激活'), (1, '已激活'), (2, '协议待同意'), (3, '维护中'), (4, '证书过期'), (5, '状态异常')) # 协议待同意和维护中:代表只读,不可创建和注册新设备号
status = models.SmallIntegerField(choices=status_choices, verbose_name="账户状态", default=0)
class Meta: class Meta:
verbose_name = '苹果开发者账户' verbose_name = '苹果开发者账户'

@ -12,6 +12,7 @@ import re
from OpenSSL.crypto import (load_pkcs12, dump_certificate_request, dump_privatekey, PKey, TYPE_RSA, X509Req, from OpenSSL.crypto import (load_pkcs12, dump_certificate_request, dump_privatekey, PKey, TYPE_RSA, X509Req,
dump_certificate, load_privatekey, load_certificate, PKCS12, FILETYPE_PEM, FILETYPE_ASN1) dump_certificate, load_privatekey, load_certificate, PKCS12, FILETYPE_PEM, FILETYPE_ASN1)
from api.models import AppIOSDeveloperInfo
from api.utils.app.shellcmds import shell_command, use_user_pass from api.utils.app.shellcmds import shell_command, use_user_pass
from api.utils.apple.appleapiv3 import AppStoreConnectApi from api.utils.apple.appleapiv3 import AppStoreConnectApi
from common.base.baseutils import get_format_time, format_apple_date, make_app_uuid from common.base.baseutils import get_format_time, format_apple_date, make_app_uuid
@ -195,7 +196,7 @@ def make_pem(cer_content, pem_path):
f.write(dump_certificate(FILETYPE_PEM, cert)) f.write(dump_certificate(FILETYPE_PEM, cert))
def check_error_call_back(error): def check_error_call_back(error, developer_pk):
msg = '' msg = ''
if 'Cannot connect to proxy' in error or 'Read timed out' in error or 'Max retries exceeded with' in error: if 'Cannot connect to proxy' in error or 'Read timed out' in error or 'Max retries exceeded with' in error:
logger.error('access apple api failed . change proxy ip again') logger.error('access apple api failed . change proxy ip again')
@ -206,16 +207,18 @@ def check_error_call_back(error):
msg = '认证失败,请检查开发者信息填写是否正确' msg = '认证失败,请检查开发者信息填写是否正确'
if 'FORBIDDEN.REQUIRED_AGREEMENTS_MISSING_OR_EXPIRED' in error: if 'FORBIDDEN.REQUIRED_AGREEMENTS_MISSING_OR_EXPIRED' in error:
msg = '请登录 https://developer.apple.com/account/ 并同意最新协议' msg = '请登录 https://developer.apple.com/account/ 并同意最新协议'
AppIOSDeveloperInfo.objects.filter(pk=developer_pk).update(status=2)
logger.error(f"{msg} {error}") logger.error(f"{msg} {error}")
return msg if msg else error return msg if msg else error
class AppDeveloperApiV2(object): class AppDeveloperApiV2(object):
def __init__(self, issuer_id, private_key_id, p8key, cert_id): def __init__(self, issuer_id, private_key_id, p8key, cert_id, developer_pk):
self.issuer_id = issuer_id self.issuer_id = issuer_id
self.private_key_id = private_key_id self.private_key_id = private_key_id
self.p8key = p8key self.p8key = p8key
self.cert_id = cert_id self.cert_id = cert_id
self.developer_pk = developer_pk
def active(self): def active(self):
result = {'data': []} result = {'data': []}
@ -230,7 +233,7 @@ class AppDeveloperApiV2(object):
return True, result return True, result
except Exception as e: except Exception as e:
logger.error(f"ios developer active Failed Exception:{e}") logger.error(f"ios developer active Failed Exception:{e}")
result['return_info'] = check_error_call_back(str(e)) result['return_info'] = check_error_call_back(str(e), self.developer_pk)
return False, result return False, result
def file_format_path_name(self, user_obj): def file_format_path_name(self, user_obj):
@ -258,7 +261,7 @@ class AppDeveloperApiV2(object):
return True, certificates return True, certificates
except Exception as e: except Exception as e:
logger.error(f"ios developer create cert Failed Exception:{e}") logger.error(f"ios developer create cert Failed Exception:{e}")
result['return_info'] = check_error_call_back(str(e)) result['return_info'] = check_error_call_back(str(e), self.developer_pk)
return False, result return False, result
def get_cert_obj_by_cid(self): def get_cert_obj_by_cid(self):
@ -273,7 +276,7 @@ class AppDeveloperApiV2(object):
return False, result return False, result
except Exception as e: except Exception as e:
logger.error(f"ios developer get cert {self.cert_id} Failed Exception:{e}") logger.error(f"ios developer get cert {self.cert_id} Failed Exception:{e}")
result['return_info'] = check_error_call_back(str(e)) result['return_info'] = check_error_call_back(str(e), self.developer_pk)
return False, result return False, result
def revoke_cert(self): def revoke_cert(self):
@ -292,7 +295,7 @@ class AppDeveloperApiV2(object):
return True, result return True, result
except Exception as e: except Exception as e:
logger.error(f"ios developer cert {self.cert_id} revoke Failed Exception:{e}") logger.error(f"ios developer cert {self.cert_id} revoke Failed Exception:{e}")
result['return_info'] = check_error_call_back(str(e)) result['return_info'] = check_error_call_back(str(e), self.developer_pk)
return False, result return False, result
def auto_set_certid_by_p12(self, app_dev_pem): def auto_set_certid_by_p12(self, app_dev_pem):
@ -312,7 +315,7 @@ class AppDeveloperApiV2(object):
return False, result return False, result
except Exception as e: except Exception as e:
logger.error(f"ios developer cert {app_dev_pem} auto get Failed Exception:{e}") logger.error(f"ios developer cert {app_dev_pem} auto get Failed Exception:{e}")
result['return_info'] = check_error_call_back(str(e)) result['return_info'] = check_error_call_back(str(e), self.developer_pk)
return False, result return False, result
def del_profile(self, profile_id, profile_name): def del_profile(self, profile_id, profile_name):
@ -323,7 +326,7 @@ class AppDeveloperApiV2(object):
return True return True
except Exception as e: except Exception as e:
logger.error(f"ios developer delete profile Failed Exception:{e}") logger.error(f"ios developer delete profile Failed Exception:{e}")
result['return_info'] = check_error_call_back(str(e)) result['return_info'] = check_error_call_back(str(e), self.developer_pk)
return False, result return False, result
def set_device_status(self, status, device_id, device_name, device_udid, failed_call_prefix, def set_device_status(self, status, device_id, device_name, device_udid, failed_call_prefix,
@ -340,7 +343,7 @@ class AppDeveloperApiV2(object):
return True, result return True, result
except Exception as e: except Exception as e:
logger.error("ios developer set devices status Failed Exception:%s" % e) logger.error("ios developer set devices status Failed Exception:%s" % e)
result['return_info'] = check_error_call_back(str(e)) result['return_info'] = check_error_call_back(str(e), self.developer_pk)
if device_err_callback and ("There are no current ios devices" in str(e) or "Device obj is None" in str(e)): if device_err_callback and ("There are no current ios devices" in str(e) or "Device obj is None" in str(e)):
with CleanErrorBundleIdSignDataState(failed_call_prefix) as state: with CleanErrorBundleIdSignDataState(failed_call_prefix) as state:
if state: if state:
@ -360,7 +363,7 @@ class AppDeveloperApiV2(object):
return True, devices_obj_list return True, devices_obj_list
except Exception as e: except Exception as e:
logger.error("ios developer get device Failed Exception:%s" % e) logger.error("ios developer get device Failed Exception:%s" % e)
result['return_info'] = check_error_call_back(str(e)) result['return_info'] = check_error_call_back(str(e), self.developer_pk)
return False, result return False, result
def del_app(self, identifier_id, bundle_id, app_id): def del_app(self, identifier_id, bundle_id, app_id):
@ -372,7 +375,7 @@ class AppDeveloperApiV2(object):
except Exception as e: except Exception as e:
logger.error("ios developer delete app Failed Exception:%s" % e) logger.error("ios developer delete app Failed Exception:%s" % e)
result['return_info'] = check_error_call_back(str(e)) result['return_info'] = check_error_call_back(str(e), self.developer_pk)
return False, result return False, result
def create_app(self, bundle_id, app_id, s_type, app_id_err_callback=None): def create_app(self, bundle_id, app_id, s_type, app_id_err_callback=None):
@ -393,7 +396,7 @@ class AppDeveloperApiV2(object):
except Exception as e: except Exception as e:
logger.error("ios developer create app Failed Exception:%s" % e) logger.error("ios developer create app Failed Exception:%s" % e)
result['return_info'] = check_error_call_back(str(e)) result['return_info'] = check_error_call_back(str(e), self.developer_pk)
if app_id_err_callback and "There is no App ID with ID" in str(e): if app_id_err_callback and "There is no App ID with ID" in str(e):
for call_fun in app_id_err_callback: for call_fun in app_id_err_callback:
call_fun() call_fun()
@ -406,7 +409,7 @@ class AppDeveloperApiV2(object):
return True, apple_obj.register_device(device_name, device_udid) return True, apple_obj.register_device(device_name, device_udid)
except Exception as e: except Exception as e:
logger.error("ios developer register device Failed Exception:%s" % e) logger.error("ios developer register device Failed Exception:%s" % e)
result['return_info'] = check_error_call_back(str(e)) result['return_info'] = check_error_call_back(str(e), self.developer_pk)
if device_err_callback and "There are no current ios devices" in str(e): if device_err_callback and "There are no current ios devices" in str(e):
with CleanErrorBundleIdSignDataState(failed_call_prefix) as state: with CleanErrorBundleIdSignDataState(failed_call_prefix) as state:
@ -437,7 +440,7 @@ class AppDeveloperApiV2(object):
return True, result return True, result
except Exception as e: except Exception as e:
logger.error(f"app_id {app_obj.app_id} ios developer make profile Failed Exception:{e}") logger.error(f"app_id {app_obj.app_id} ios developer make profile Failed Exception:{e}")
result['return_info'] = check_error_call_back(str(e)) result['return_info'] = check_error_call_back(str(e), self.developer_pk)
if app_id_err_callback and "There is no App ID with ID" in str(e): if app_id_err_callback and "There is no App ID with ID" in str(e):
with CleanErrorBundleIdSignDataState(failed_call_prefix) as state: with CleanErrorBundleIdSignDataState(failed_call_prefix) as state:
if state: if state:
@ -471,5 +474,5 @@ class AppDeveloperApiV2(object):
return True, result return True, result
except Exception as e: except Exception as e:
logger.error("ios developer modify_capability Failed Exception:%s" % e) logger.error("ios developer modify_capability Failed Exception:%s" % e)
result['return_info'] = check_error_call_back(str(e)) result['return_info'] = check_error_call_back(str(e), self.developer_pk)
return False, result return False, result

@ -187,9 +187,10 @@ def get_auth_form_developer(developer_obj):
return auth return auth
def get_api_obj(auth): def get_api_obj(developer_obj):
auth = get_auth_form_developer(developer_obj)
if auth.get("issuer_id"): if auth.get("issuer_id"):
app_api_obj = AppDeveloperApiV2(**auth) app_api_obj = AppDeveloperApiV2(**auth, developer_pk=developer_obj.pk)
else: else:
app_api_obj = None app_api_obj = None
return app_api_obj return app_api_obj
@ -212,17 +213,16 @@ def err_callback(func, *args, **kwargs):
def disable_developer_and_send_email(app_obj, developer_obj): def disable_developer_and_send_email(app_obj, developer_obj):
logger.error(f"app {app_obj} developer {developer_obj} sign failed. so disabled") logger.error(f"app {app_obj} developer {developer_obj} sign failed. so disabled")
developer_obj.is_actived = False developer_obj.status = 5
developer_obj.save(update_fields=['is_actived']) developer_obj.save(update_fields=['status'])
send_ios_developer_active_status(developer_obj.user_id, send_ios_developer_active_status(developer_obj.user_id,
MSGTEMPLATE.get('ERROR_DEVELOPER') % ( MSGTEMPLATE.get('ERROR_DEVELOPER') % (
developer_obj.user_id.first_name, app_obj.name, developer_obj.user_id.first_name, app_obj.name,
developer_obj.issuer_id)) developer_obj.issuer_id))
def get_new_developer_by_app_obj(user_objs, app_obj, apple_to_app=False): def get_new_developer_by_app_obj(app_obj, obj_base_filter, apple_to_app=False):
can_used_developer_pk_list = [] can_used_developer_pk_list = []
obj_base_filter = AppIOSDeveloperInfo.objects.filter(user_id__in=user_objs, is_actived=True, certid__isnull=False)
if apple_to_app: if apple_to_app:
# 存在指定开发者,则新设备优先注册到指定开发者 # 存在指定开发者,则新设备优先注册到指定开发者
developer_obj_lists = obj_base_filter.filter(appledevelopertoappuse__app_id=app_obj) developer_obj_lists = obj_base_filter.filter(appledevelopertoappuse__app_id=app_obj)
@ -250,9 +250,7 @@ def get_new_developer_by_app_obj(user_objs, app_obj, apple_to_app=False):
def filter_developer_by_pk_list(developer_pk_list, f_key, app_search_flag=True): def filter_developer_by_pk_list(developer_pk_list, f_key, app_search_flag=True):
developer_obj_dict = AppIOSDeveloperInfo.objects.filter(pk__in=developer_pk_list, developer_obj_dict = AppIOSDeveloperInfo.objects.filter(pk__in=developer_pk_list).values(
is_actived=True,
certid__isnull=False).values(
f_key, 'pk').annotate(count=Count('pk')) f_key, 'pk').annotate(count=Count('pk'))
if not app_search_flag: if not app_search_flag:
developer_obj_dict = developer_obj_dict.filter(count__lt=F('app_limit_number')) developer_obj_dict = developer_obj_dict.filter(count__lt=F('app_limit_number'))
@ -268,18 +266,24 @@ def get_developer_by_pk_list(developer_pk_list, f_key, app_search_flag=True):
return developer_obj return developer_obj
def get_developer_user_by_app_udid(user_objs, udid, app_obj, private_first=True): def get_developer_user_by_app_udid(user_objs, udid, app_obj, private_first=True, read_only=True):
""" """
:param read_only:
:param user_objs: [user_obj] :param user_objs: [user_obj]
:param udid: udid :param udid: udid
:param app_obj: app_obj :param app_obj: app_obj
:param private_first: 专属应用优先使用专属开发者而不是公共开发者 :param private_first: 专属应用优先使用专属开发者而不是公共开发者
:return: (developer_obj, is_exist_devices) :return: (developer_obj, is_exist_devices)
""" """
if read_only:
status_choice = [1, 2, 3, 4, 5]
else:
status_choice = [1]
status_filter = {'developerid__certid__isnull': False, 'developerid__status__in': status_choice}
developer_udid_queryset = UDIDsyncDeveloper.objects.filter(developerid__user_id__in=user_objs, developer_udid_queryset = UDIDsyncDeveloper.objects.filter(developerid__user_id__in=user_objs,
developerid__is_actived=True, **status_filter).values('developerid').all().distinct()
developerid__certid__isnull=False).values(
'developerid').all().distinct()
# 根据udid和应用查找该用户开发者账户【主要可能是开发者未激活】 # 根据udid和应用查找该用户开发者账户【主要可能是开发者未激活】
developer_pk_list = developer_udid_queryset.filter(udid=udid, developerid__apptodeveloper__app_id=app_obj) developer_pk_list = developer_udid_queryset.filter(udid=udid, developerid__apptodeveloper__app_id=app_obj)
@ -317,8 +321,7 @@ def get_developer_user_by_app_udid(user_objs, udid, app_obj, private_first=True)
exist_app_developer_pk_list.append(developer_obj.pk) exist_app_developer_pk_list.append(developer_obj.pk)
# 查询状态正常的专属开发者信息,判断是否为专属应用 # 查询状态正常的专属开发者信息,判断是否为专属应用
apple_to_app = AppleDeveloperToAppUse.objects.filter(app_id=app_obj, developerid__is_actived=True, apple_to_app = AppleDeveloperToAppUse.objects.filter(app_id=app_obj, **status_filter).first()
developerid__certid__isnull=False).first()
# 存在专属开发者账户,但是也同时存在已经安装的设备,优先选择已经安装设备的开发者账户?是or否 # 存在专属开发者账户,但是也同时存在已经安装的设备,优先选择已经安装设备的开发者账户?是or否
# 是:使应用趋向于一个开发者,为后期更新提供方便 # 是:使应用趋向于一个开发者,为后期更新提供方便
@ -326,12 +329,15 @@ def get_developer_user_by_app_udid(user_objs, udid, app_obj, private_first=True)
if not private_first and apple_to_app and exist_app_developer_pk_list: if not private_first and apple_to_app and exist_app_developer_pk_list:
return AppIOSDeveloperInfo.objects.filter(pk=exist_app_developer_pk_list[0]).first(), False return AppIOSDeveloperInfo.objects.filter(pk=exist_app_developer_pk_list[0]).first(), False
can_used_developer_pk_list = get_new_developer_by_app_obj(user_objs, app_obj, apple_to_app) status_filter = {'certid__isnull': False, 'status__in': status_choice}
obj_base_filter = AppIOSDeveloperInfo.objects.filter(user_id__in=user_objs, **status_filter)
can_used_developer_pk_list = get_new_developer_by_app_obj(app_obj, obj_base_filter, apple_to_app)
# 存在指定开发者账户,但是获取可用的开发者账户为空,那么开始匹配全部开发者 # 存在指定开发者账户,但是获取可用的开发者账户为空,那么开始匹配全部开发者
if not can_used_developer_pk_list and apple_to_app: if not can_used_developer_pk_list and apple_to_app:
logger.info(f"udid:{udid} app_obj:{app_obj} private developer is null. start find all developer") logger.info(f"udid:{udid} app_obj:{app_obj} private developer is null. start find all developer")
can_used_developer_pk_list = get_new_developer_by_app_obj(user_objs, app_obj) can_used_developer_pk_list = get_new_developer_by_app_obj(app_obj, obj_base_filter)
if can_used_developer_pk_list and exist_app_developer_pk_list: if can_used_developer_pk_list and exist_app_developer_pk_list:
can_used_developer_pk_list = list(set(can_used_developer_pk_list) & set(exist_app_developer_pk_list)) can_used_developer_pk_list = list(set(can_used_developer_pk_list) & set(exist_app_developer_pk_list))
@ -346,14 +352,14 @@ def get_developer_user_by_app_udid(user_objs, udid, app_obj, private_first=True)
return None, None return None, None
def get_developer_obj_by_others(user_obj, udid, app_obj): def get_developer_obj_by_others(user_obj, udid, app_obj, read_only):
result, is_exist = get_developer_user_by_app_udid([user_obj], udid, app_obj) result, is_exist = get_developer_user_by_app_udid([user_obj], udid, app_obj, read_only=read_only)
if result: if result:
return result return result
receive_user_id_list = IosDeveloperPublicPoolBill.objects.filter(to_user_id=user_obj).values('user_id').distinct() receive_user_id_list = IosDeveloperPublicPoolBill.objects.filter(to_user_id=user_obj).values('user_id').distinct()
if receive_user_id_list: if receive_user_id_list:
result, is_exist = get_developer_user_by_app_udid(UserInfo.objects.filter(pk__in=receive_user_id_list), udid, result, is_exist = get_developer_user_by_app_udid(UserInfo.objects.filter(pk__in=receive_user_id_list), udid,
app_obj) app_obj, read_only=read_only)
f_count = get_ios_developer_public_num(user_obj) f_count = get_ios_developer_public_num(user_obj)
if (f_count == 0 and is_exist) or f_count > 0: if (f_count == 0 and is_exist) or f_count > 0:
@ -370,8 +376,8 @@ class IosUtils(object):
self.user_obj = user_obj self.user_obj = user_obj
self.get_developer_auth() self.get_developer_auth()
def get_developer_auth(self): def get_developer_auth(self, read_only=True):
self.developer_obj = get_developer_obj_by_others(self.user_obj, self.udid, self.app_obj) self.developer_obj = get_developer_obj_by_others(self.user_obj, self.udid, self.app_obj, read_only)
if self.developer_obj: if self.developer_obj:
self.auth = get_auth_form_developer(self.developer_obj) self.auth = get_auth_form_developer(self.developer_obj)
else: else:
@ -399,8 +405,7 @@ class IosUtils(object):
@staticmethod @staticmethod
def modify_capability(developer_obj, app_obj, developer_app_id): def modify_capability(developer_obj, app_obj, developer_app_id):
auth = get_auth_form_developer(developer_obj) return get_api_obj(developer_obj).modify_capability(app_obj, developer_app_id)
return get_api_obj(auth).modify_capability(app_obj, developer_app_id)
def get_profile_full_path(self): def get_profile_full_path(self):
cert_dir_name = make_app_uuid(self.user_obj, get_apple_udid_key(self.auth)) cert_dir_name = make_app_uuid(self.user_obj, get_apple_udid_key(self.auth))
@ -553,16 +558,18 @@ class IosUtils(object):
return True, 'continue' return True, 'continue'
sync_device_obj = UDIDsyncDeveloper.objects.filter(udid=device_udid, sync_device_obj = UDIDsyncDeveloper.objects.filter(udid=device_udid,
developerid=developer_obj).first() developerid=developer_obj).first()
auth = get_auth_form_developer(developer_obj) # auth = get_auth_form_developer(developer_obj)
# 库里面存在,并且设备是可用状态,因此无需api注册 # 库里面存在,并且设备是可用状态,因此无需api注册
if sync_device_obj: if sync_device_obj:
logger.info(f"app {app_obj} device {sync_device_obj.serial} already in developer {developer_obj}") logger.info(f"app {app_obj} device {sync_device_obj.serial} already in developer {developer_obj}")
if not sync_device_obj.status: if not sync_device_obj.status:
# 库里面存在,并且设备是禁用状态,需要调用api启用 # 库里面存在,并且设备是禁用状态,需要调用api启用
status, result = get_api_obj(auth).set_device_status("enable", sync_device_obj.serial, status, result = get_api_obj(developer_obj).set_device_status("enable", sync_device_obj.serial,
sync_device_obj.product, sync_device_obj.udid, sync_device_obj.product,
failed_call_prefix, sync_device_obj.udid,
err_callback(IosUtils.get_device_from_developer, failed_call_prefix,
err_callback(
IosUtils.get_device_from_developer,
developer_obj)) developer_obj))
if not status: # 已经包含异常操作,暂定 if not status: # 已经包含异常操作,暂定
return status, result return status, result
@ -570,8 +577,10 @@ class IosUtils(object):
sync_device_obj.save(update_fields=['status']) sync_device_obj.save(update_fields=['status'])
else: else:
# 库里面不存在,注册设备,新设备注册默认就是启用状态 # 库里面不存在,注册设备,新设备注册默认就是启用状态
status, device_obj = get_api_obj(auth).register_device(device_udid, device_name, failed_call_prefix, status, device_obj = get_api_obj(developer_obj).register_device(device_udid, device_name,
err_callback(IosUtils.get_device_from_developer, failed_call_prefix,
err_callback(
IosUtils.get_device_from_developer,
developer_obj)) developer_obj))
if not status: if not status:
return status, device_obj return status, device_obj
@ -620,11 +629,10 @@ class IosUtils(object):
developer_app_id_obj = DeveloperAppID.objects.filter(developerid=developer_obj, developer_app_id_obj = DeveloperAppID.objects.filter(developerid=developer_obj,
app_id=app_obj).first() app_id=app_obj).first()
if not developer_app_id_obj: if not developer_app_id_obj:
auth = get_auth_form_developer(developer_obj)
bundle_id = app_obj.bundle_id bundle_id = app_obj.bundle_id
app_id = app_obj.app_id app_id = app_obj.app_id
s_type = app_obj.supersign_type s_type = app_obj.supersign_type
status, result = get_api_obj(auth).create_app(bundle_id, app_id, s_type, failed_callback) status, result = get_api_obj(developer_obj).create_app(bundle_id, app_id, s_type, failed_callback)
if status and result.get('aid'): if status and result.get('aid'):
developer_app_id_obj = DeveloperAppID.objects.create(aid=result.get('aid'), developerid=developer_obj, developer_app_id_obj = DeveloperAppID.objects.create(aid=result.get('aid'), developerid=developer_obj,
app_id=app_obj) app_id=app_obj)
@ -659,12 +667,13 @@ class IosUtils(object):
developer_app_id = developer_app_id_obj.aid developer_app_id = developer_app_id_obj.aid
profile_id = developer_app_id_obj.profile_id profile_id = developer_app_id_obj.profile_id
auth = get_auth_form_developer(developer_obj) auth = get_auth_form_developer(developer_obj)
status, result = get_api_obj(auth).make_and_download_profile(app_obj, status, result = get_api_obj(developer_obj).make_and_download_profile(app_obj,
get_profile_full_path(developer_obj, app_obj), get_profile_full_path(developer_obj,
auth, developer_app_id, app_obj),
device_id_lists, profile_id, auth, developer_app_id,
failed_call_prefix, failed_callback, device_id_lists, profile_id,
) failed_call_prefix, failed_callback,
)
if not status: if not status:
return False, result return False, result
@ -690,6 +699,8 @@ class IosUtils(object):
if result: if result:
return result return result
self.get_developer_auth(read_only=False)
logger.info("udid %s not exists app_id %s ,need sign" % (self.udid, self.app_obj)) logger.info("udid %s not exists app_id %s ,need sign" % (self.udid, self.app_obj))
if consume_user_download_times_by_app_obj(self.app_obj): if consume_user_download_times_by_app_obj(self.app_obj):
@ -835,8 +846,7 @@ class IosUtils(object):
@staticmethod @staticmethod
def do_disable_device(developer_obj, udid_lists, udid_obj): def do_disable_device(developer_obj, udid_lists, udid_obj):
if udid_lists.count((udid_obj.udid.udid,)) == 1: if udid_lists.count((udid_obj.udid.udid,)) == 1:
auth = get_auth_form_developer(developer_obj) app_api_obj = get_api_obj(developer_obj)
app_api_obj = get_api_obj(auth)
app_api_obj.set_device_status("disable", udid_obj.udid.serial, udid_obj.udid.product, udid_obj.udid.udid, app_api_obj.set_device_status("disable", udid_obj.udid.serial, udid_obj.udid.product, udid_obj.udid.udid,
udid_obj.udid.udid) udid_obj.udid.udid)
UDIDsyncDeveloper.objects.filter(udid=udid_obj.udid.udid, developerid=developer_obj).update(status=False) UDIDsyncDeveloper.objects.filter(udid=udid_obj.udid.udid, developerid=developer_obj).update(status=False)
@ -883,12 +893,11 @@ class IosUtils(object):
@staticmethod @staticmethod
def clean_app_by_developer_obj(app_obj, developer_obj): def clean_app_by_developer_obj(app_obj, developer_obj):
auth = get_auth_form_developer(developer_obj)
developer_app_id_obj = DeveloperAppID.objects.filter(developerid=developer_obj, app_id=app_obj).first() developer_app_id_obj = DeveloperAppID.objects.filter(developerid=developer_obj, app_id=app_obj).first()
if developer_app_id_obj: if developer_app_id_obj:
app_api_obj = get_api_obj(auth) app_api_obj = get_api_obj(developer_obj)
app_api_obj.del_profile(developer_app_id_obj.profile_id, app_obj.app_id) app_api_obj.del_profile(developer_app_id_obj.profile_id, app_obj.app_id)
app_api_obj2 = get_api_obj(auth) app_api_obj2 = get_api_obj(developer_obj)
app_api_obj2.del_app(developer_app_id_obj.aid, app_obj.bundle_id, app_obj.app_id) app_api_obj2.del_app(developer_app_id_obj.aid, app_obj.bundle_id, app_obj.app_id)
developer_app_id_obj.delete() developer_app_id_obj.delete()
@ -930,8 +939,7 @@ class IosUtils(object):
:param developer_obj: :param developer_obj:
:return: :return:
""" """
auth = get_auth_form_developer(developer_obj) app_api_obj = get_api_obj(developer_obj)
app_api_obj = get_api_obj(auth)
status, result = app_api_obj.active() status, result = app_api_obj.active()
if status: if status:
cert_is_exists = True cert_is_exists = True
@ -946,10 +954,8 @@ class IosUtils(object):
IosUtils.clean_developer(developer_obj, developer_obj.user_id) IosUtils.clean_developer(developer_obj, developer_obj.user_id)
developer_obj.certid = None developer_obj.certid = None
developer_obj.cert_expire_time = None developer_obj.cert_expire_time = None
developer_obj.is_actived = True developer_obj.status = 1
else: developer_obj.save(update_fields=['certid', 'cert_expire_time', 'status'])
developer_obj.is_actived = False
developer_obj.save(update_fields=['certid', 'cert_expire_time', 'is_actived'])
return status, result return status, result
@staticmethod @staticmethod
@ -961,36 +967,32 @@ class IosUtils(object):
@staticmethod @staticmethod
def create_developer_cert(developer_obj, user_obj): def create_developer_cert(developer_obj, user_obj):
auth = get_auth_form_developer(developer_obj) app_api_obj = get_api_obj(developer_obj)
app_api_obj = get_api_obj(auth)
status, result = app_api_obj.create_cert(user_obj) status, result = app_api_obj.create_cert(user_obj)
if status: if status:
if auth.get("issuer_id"): cert_id = result.id
cert_id = result.id AppIOSDeveloperInfo.objects.filter(user_id=user_obj, issuer_id=auth.get("issuer_id")).update(
AppIOSDeveloperInfo.objects.filter(user_id=user_obj, issuer_id=auth.get("issuer_id")).update( status=1,
is_actived=True, certid=cert_id, cert_expire_time=format_apple_date(result.expirationDate))
certid=cert_id, cert_expire_time=format_apple_date(result.expirationDate)) resign_app_obj = IosUtils.get_resign_obj(user_obj, developer_obj)
resign_app_obj = IosUtils.get_resign_obj(user_obj, developer_obj) resign_app_obj.make_p12_from_cert(cert_id)
resign_app_obj.make_p12_from_cert(cert_id)
return status, result return status, result
@staticmethod @staticmethod
def revoke_developer_cert(developer_obj, user_obj): def revoke_developer_cert(developer_obj, user_obj):
auth = get_auth_form_developer(developer_obj) app_api_obj = get_api_obj(developer_obj)
app_api_obj = get_api_obj(auth)
status, result = app_api_obj.revoke_cert() status, result = app_api_obj.revoke_cert()
if not status: if not status:
logger.warning('%s revoke cert failed,but i need clean cert_id %s' % (developer_obj.issuer_id, result)) logger.warning('%s revoke cert failed,but i need clean cert_id %s' % (developer_obj.issuer_id, result))
AppIOSDeveloperInfo.objects.filter(user_id=user_obj, issuer_id=auth.get("issuer_id")).update( AppIOSDeveloperInfo.objects.filter(user_id=user_obj, issuer_id=developer_obj.issuer_id).update(
is_actived=True, status=4,
certid=None, cert_expire_time=None) certid=None, cert_expire_time=None)
return status, result return status, result
@staticmethod @staticmethod
def check_developer_cert(developer_obj, user_obj): def check_developer_cert(developer_obj, user_obj):
# 暂时无用 # 暂时无用
auth = get_auth_form_developer(developer_obj) app_api_obj = get_api_obj(developer_obj)
app_api_obj = get_api_obj(auth)
status, result = app_api_obj.get_cert_obj_by_cid() status, result = app_api_obj.get_cert_obj_by_cid()
if not status: if not status:
AppIOSDeveloperInfo.objects.filter(user_id=user_obj, issuer_id=auth.get("issuer_id")).update( AppIOSDeveloperInfo.objects.filter(user_id=user_obj, issuer_id=auth.get("issuer_id")).update(
@ -1000,22 +1002,21 @@ class IosUtils(object):
@staticmethod @staticmethod
def auto_get_cert_id_by_p12(developer_obj, user_obj): def auto_get_cert_id_by_p12(developer_obj, user_obj):
auth = get_auth_form_developer(developer_obj) auth = get_auth_form_developer(developer_obj)
app_api_obj = get_api_obj(auth) app_api_obj = get_api_obj(developer_obj)
file_format_path_name = file_format_path(user_obj, auth) file_format_path_name = file_format_path(user_obj, auth)
app_dev_pem = file_format_path_name + ".pem.bak" app_dev_pem = file_format_path_name + ".pem.bak"
status, result = app_api_obj.auto_set_certid_by_p12(app_dev_pem) status, result = app_api_obj.auto_set_certid_by_p12(app_dev_pem)
if status: if status:
AppIOSDeveloperInfo.objects.filter(user_id=user_obj, issuer_id=auth.get("issuer_id")).update( AppIOSDeveloperInfo.objects.filter(user_id=user_obj, issuer_id=auth.get("issuer_id")).update(
is_actived=True, status=1,
certid=result.id, cert_expire_time=format_apple_date(result.expirationDate)) certid=result.id, cert_expire_time=format_apple_date(result.expirationDate))
return status, result return status, result
@staticmethod @staticmethod
def get_device_from_developer(developer_obj): def get_device_from_developer(developer_obj):
auth = get_auth_form_developer(developer_obj) app_api_obj = get_api_obj(developer_obj)
app_api_obj = get_api_obj(auth)
status, result = app_api_obj.get_device() status, result = app_api_obj.get_device()
if status and auth.get("issuer_id"): if status and developer_obj.issuer_id:
udid_developer_obj_list = UDIDsyncDeveloper.objects.filter(developerid=developer_obj).values_list('udid') udid_developer_obj_list = UDIDsyncDeveloper.objects.filter(developerid=developer_obj).values_list('udid')
udid_developer_list = [x[0] for x in udid_developer_obj_list if len(x) > 0] udid_developer_list = [x[0] for x in udid_developer_obj_list if len(x) > 0]

@ -703,7 +703,8 @@ def call_function_try_attempts(try_attempts=5, sleep_time=3):
f'exec {func} failed. Failed:{e} {try_attempts} times in total. now {sleep_time} later try ' f'exec {func} failed. Failed:{e} {try_attempts} times in total. now {sleep_time} later try '
f'again...{i}') f'again...{i}')
res = str(e) res = str(e)
if 'Authentication credentials are missing or invalid' in str(e): if 'Authentication credentials are missing or invalid' in str(
e) or 'FORBIDDEN.REQUIRED_AGREEMENTS_MISSING_OR_EXPIRED' in str(e):
raise Exception(res) raise Exception(res)
time.sleep(sleep_time) time.sleep(sleep_time)
logger.info(f"exec {func} finished. time:{time.time() - start_time}") logger.info(f"exec {func} finished. time:{time.time() - start_time}")

@ -65,9 +65,11 @@ def auto_delete_ios_mobile_tmp_file():
def auto_check_ios_developer_active(): def auto_check_ios_developer_active():
all_ios_developer = AppIOSDeveloperInfo.objects.filter(is_actived=True) all_ios_developer = AppIOSDeveloperInfo.objects.filter(status=1)
error_issuer_id = {}
for ios_developer in all_ios_developer: for ios_developer in all_ios_developer:
userinfo = ios_developer.user_id userinfo = ios_developer.user_id
err_issuer_id = error_issuer_id.get(userinfo.uid, [])
if userinfo.supersign_active: if userinfo.supersign_active:
count = 3 count = 3
while count > 0: while count > 0:
@ -81,8 +83,10 @@ def auto_check_ios_developer_active():
count -= 1 count -= 1
time.sleep(5) time.sleep(5)
if count == 0: if count == 0:
ios_developer.is_actived = False err_issuer_id.append(ios_developer.issuer_id)
ios_developer.save(update_fields=['is_actived'])
logger.error(msg) logger.error(msg)
send_ios_developer_active_status(userinfo, MSGTEMPLATE.get('AUTO_CHECK_DEVELOPER') % ( error_issuer_id[userinfo.uid] = list(set(err_issuer_id))
userinfo.first_name, ios_developer.issuer_id)) for uid, val in error_issuer_id.items():
userinfo = UserInfo.objects.filter(uid=uid).first()
send_ios_developer_active_status(userinfo, MSGTEMPLATE.get('AUTO_CHECK_DEVELOPER') % (
userinfo.first_name, ",".join(val)))

@ -526,7 +526,8 @@ class DeveloperSerializer(serializers.ModelSerializer):
def get_is_disabled(self, obj): def get_is_disabled(self, obj):
app_id = self.context.get('app_id', '') app_id = self.context.get('app_id', '')
if app_id: if app_id:
developer_app_obj = models.DeveloperAppID.objects.filter(developerid=obj, developerid__is_actived=True, developer_app_obj = models.DeveloperAppID.objects.filter(developerid=obj,
developerid__status__in=[1, 2, 3, 4, 5],
developerid__certid__isnull=False) developerid__certid__isnull=False)
if developer_app_obj.filter(app_id__app_id=app_id).distinct().count(): if developer_app_obj.filter(app_id__app_id=app_id).distinct().count():
return False return False

@ -61,13 +61,13 @@ def get_developer_devices(developer_obj_lists):
other_used_sum = 0 other_used_sum = 0
flyapp_used_sum = 0 flyapp_used_sum = 0
max_total = 0 max_total = 0
for dev_obj in developer_obj_lists.filter(is_actived=True): for dev_obj in developer_obj_lists.filter(status__in=[1, 2, 3, 4, 5]):
other_used, flyapp_used, _ = get_developer_udided(dev_obj) other_used, flyapp_used, _ = get_developer_udided(dev_obj)
other_used_sum += other_used other_used_sum += other_used
flyapp_used_sum += flyapp_used flyapp_used_sum += flyapp_used
max_total += 100 max_total += 100
use_number_obj_list = developer_obj_lists.filter(is_actived=True) use_number_obj_list = developer_obj_lists.filter(status__in=[1, 2, 3, 4, 5])
all_use_number = 0 all_use_number = 0
all_usable_number = 0 all_usable_number = 0
for use_number_obj in use_number_obj_list: for use_number_obj in use_number_obj_list:

@ -64,12 +64,13 @@ class DeveloperView(APIView):
res.data = developer_serializer.data res.data = developer_serializer.data
res.count = developer_obj.count() res.count = developer_obj.count()
res.status_choices = get_choices_dict(AppIOSDeveloperInfo.status_choices)
res.apple_auth_list = get_choices_dict(AppIOSDeveloperInfo.auth_type_choices) res.apple_auth_list = get_choices_dict(AppIOSDeveloperInfo.auth_type_choices)
return Response(res.dict) return Response(res.dict)
def put(self, request): def put(self, request):
data = request.data data = request.data
res = BaseResponse()
issuer_id = data.get("issuer_id", "").strip() issuer_id = data.get("issuer_id", "").strip()
if issuer_id: if issuer_id:
developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=request.user, issuer_id=issuer_id).first() developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=request.user, issuer_id=issuer_id).first()
@ -78,26 +79,26 @@ class DeveloperView(APIView):
if act == "syncalldevice": if act == "syncalldevice":
res = BaseResponse() res = BaseResponse()
result_list = [] result_list = []
for developer_s_obj in AppIOSDeveloperInfo.objects.filter(user_id=request.user, is_actived=True).all(): for developer_s_obj in AppIOSDeveloperInfo.objects.filter(user_id=request.user,
status__in=[1, 2, 3, 4, 5]).all():
status, result = IosUtils.get_device_from_developer(developer_s_obj) status, result = IosUtils.get_device_from_developer(developer_s_obj)
if not status: if not status:
result_list.append(result.get("err_info")) result_list.append(result.get("err_info"))
if len(result_list): if len(result_list):
logger.warning(result_list) logger.warning(result_list)
return Response(res.dict) return Response(res.dict)
return self.get(request) return Response(res.dict)
if developer_obj: if developer_obj:
act = data.get("act", "").strip() act = data.get("act", "").strip()
if act: if act:
res = BaseResponse()
logger.info(f"user {request.user} ios developer {developer_obj} act {act}") logger.info(f"user {request.user} ios developer {developer_obj} act {act}")
if act == "checkauth": if act == "checkauth":
status, result = IosUtils.active_developer(developer_obj) status, result = IosUtils.active_developer(developer_obj)
if status: if status:
if not developer_obj.certid: if not developer_obj.certid:
IosUtils.get_device_from_developer(developer_obj) IosUtils.get_device_from_developer(developer_obj)
return self.get(request) return Response(res.dict)
else: else:
res.code = 1008 res.code = 1008
res.msg = result.get("return_info", "未知错误") res.msg = result.get("return_info", "未知错误")
@ -148,9 +149,9 @@ class DeveloperView(APIView):
res.msg = "数据清理中,请耐心等待" res.msg = "数据清理中,请耐心等待"
return Response(res.dict) return Response(res.dict)
elif act == 'disable': elif act == 'disable':
developer_obj.is_actived = False developer_obj.status = 0
developer_obj.save(update_fields=['is_actived']) developer_obj.save(update_fields=['status'])
return self.get(request) return Response(res.dict)
else: else:
update_fields = [] update_fields = []
logger.info(f"user {request.user} ios developer {developer_obj} update input data {data}") logger.info(f"user {request.user} ios developer {developer_obj} update input data {data}")
@ -175,14 +176,20 @@ class DeveloperView(APIView):
p8key = data.get("p8key", developer_obj.p8key) p8key = data.get("p8key", developer_obj.p8key)
if private_key_id != "" and private_key_id != developer_obj.private_key_id: if private_key_id != "" and private_key_id != developer_obj.private_key_id:
developer_obj.private_key_id = private_key_id developer_obj.private_key_id = private_key_id
developer_obj.is_actived = False developer_obj.status = 0
update_fields.append("private_key_id") update_fields.append("private_key_id")
if p8key != "" and p8key != developer_obj.p8key: if p8key != "" and p8key != developer_obj.p8key:
developer_obj.p8key = p8key developer_obj.p8key = p8key
developer_obj.is_actived = False developer_obj.status = 0
update_fields.append("p8key") update_fields.append("p8key")
read_only_mode = data.get("read_only_mode", '')
if developer_obj.status == 1 and read_only_mode == 'on':
developer_obj.status = 3
update_fields.append("status")
try: try:
update_fields.append("is_actived") update_fields.append("status")
developer_obj.save(update_fields=update_fields) developer_obj.save(update_fields=update_fields)
logger.info( logger.info(
f"user {request.user} ios developer {developer_obj} update now data {developer_obj.__dict__}") f"user {request.user} ios developer {developer_obj} update now data {developer_obj.__dict__}")
@ -190,7 +197,7 @@ class DeveloperView(APIView):
logger.error( logger.error(
f"user {request.user} ios developer {developer_obj} update error data {data} Exception {e}") f"user {request.user} ios developer {developer_obj} update error data {data} Exception {e}")
return self.get(request) return Response(res.dict)
def post(self, request): def post(self, request):
data = request.data data = request.data
@ -538,7 +545,8 @@ class AppleDeveloperBindAppsView(APIView):
for item in add_issuer_ids: for item in add_issuer_ids:
developer_obj = AppIOSDeveloperInfo.objects.filter(issuer_id=item, user_id=request.user, developer_obj = AppIOSDeveloperInfo.objects.filter(issuer_id=item, user_id=request.user,
is_actived=True, certid__isnull=False).first() status__in=[1, 2, 3, 4, 5],
certid__isnull=False).first()
developer_aid_obj = DeveloperAppID.objects.filter(developerid=developer_obj) developer_aid_obj = DeveloperAppID.objects.filter(developerid=developer_obj)
is_exist = developer_aid_obj.filter(app_id=app_obj).count() is_exist = developer_aid_obj.filter(app_id=app_obj).count()
if developer_obj: if developer_obj:

Loading…
Cancel
Save