增加签名应用限额

增加应用签名后包下载
优化代码
qrnn
MMXX 3 years ago
parent def6c9dfc8
commit f8418f6414
  1. 5
      fir_client/src/components/FirBase.vue
  2. 15
      fir_client/src/components/apps/FirAppInfossupersign.vue
  3. 3
      fir_client/src/components/apps/FirAppInfostimeline.vue
  4. 60
      fir_client/src/components/base/AppleDeveloperBindApp.vue
  5. 57
      fir_client/src/components/user/FirSuperSignBase.vue
  6. 2
      fir_client/vue.config.js
  7. 17
      fir_ser/api/migrations/0027_appiosdeveloperinfo_app_limit_number.py
  8. 7
      fir_ser/api/models.py
  9. 30
      fir_ser/api/utils/app/supersignutils.py
  10. 17
      fir_ser/api/utils/serializer.py
  11. 47
      fir_ser/api/utils/storage/caches.py
  12. 48
      fir_ser/api/views/download.py
  13. 58
      fir_ser/api/views/supersign.py

@ -19,7 +19,7 @@
type="error">
<div slot="title">
<span class="domian-tip-bar">应用分发请绑定您自己的域名平台分发域名可能因不可违因素更换将导致您的应用无法访问</span>
<el-button size="medium" @click="bind_domain_type=1,bind_domain_sure=true">立即绑定</el-button>
<el-button size="small" @click="bind_domain_type=1,bind_domain_sure=true">立即绑定</el-button>
</div>
</el-alert>
</div>
@ -125,4 +125,7 @@ export default {
font-size: medium;
margin-right: 20px;
}
/deep/ .el-alert{
padding: 2px 16px;
}
</style>

@ -1,7 +1,7 @@
<template>
<div style="margin-top: 20px;width: 66%;margin-left: 8%">
<div style="margin-top: 20px;width: 72%;margin-left: 8%">
<el-dialog
:close-on-click-modal="false"
:close-on-press-escape="false"
@ -30,12 +30,17 @@
<el-button v-if="!currentapp.issupersign && currentapp.count !== 0" plain
size="small" style="margin-left: 20px" type="info" @click="clean_app">清理该应用脏数据
</el-button>
<el-link v-else :underline="false" style="margin-left: 20px">超级签名iOS专用需要配置好苹果开发者账户方可开启</el-link>
<!-- <el-link v-else :underline="false" style="margin-left: 20px">超级签名iOS专用需要配置好苹果开发者账户方可开启</el-link>-->
<el-tooltip content="点击查看所使用开发者信息" placement="top">
<el-link :disabled="supersign_disable" :underline="false" style="margin-left: 20px;color: #3875cc;"
@click="$router.push({name:'FirSuperSignBase',params:{act:'iosdeveloper'},query:{appidseach: currentapp.bundle_id}})">
使用了 {{ currentapp.developer_used_count }} 开发者
</el-link>
</el-tooltip>
</el-form-item>
<el-form-item label="专属配置" label-width="200px">
<el-button :disabled="supersign_disable" @click="bindAppletoapp">配置专属苹果开发账户</el-button>
<el-link :underline="false" style="margin-left: 20px" @click="bindAppletoapp"> 拥有
<el-link :disabled="supersign_disable" :underline="false" style="margin-left: 20px" @click="bindAppletoapp"> 拥有
{{ currentapp.private_developer_number }} 个专属苹果开发者使用了 {{ currentapp.private_developer_used_number }} 个设备数
</el-link>
</el-form-item>
@ -52,7 +57,7 @@
>保存
</el-button>
<el-tooltip content="点击查看使用详情" placement="top">
<el-link :underline="false" style="margin-left: 20px" type="primary"
<el-link :disabled="supersign_disable" :underline="false" style="margin-left: 20px" type="primary"
@click="$router.push({name:'FirSuperSignBase',params:{act:'useddevices'},query:{bundleid: currentapp.bundle_id}})">
已经使用 <a style="color: #dd6161;font-size: larger">{{ currentapp.supersign_used_number }}</a>
个设备额度

@ -78,7 +78,8 @@
</el-tooltip>
<el-button class="tooltip-top" @click="previewRelase(app)"><i class="el-icon-view"/> <span
<el-button v-if="!currentapp.issupersign" class="tooltip-top" @click="previewRelase(app)"><i
class="el-icon-view"/> <span
class="ng-binding">预览</span>
</el-button>

@ -24,6 +24,7 @@
<el-tag v-else type="info">公共应用账户所有应用公用此开发者</el-tag>
<p>开发者ID: {{ option.issuer_id }} </p>
<p>应用签名数: {{ option.app_used_count }} </p>
<p>应用签名数限额: {{ option.app_limit_number }} </p>
<p>已分配专属应用数: {{ option.app_private_number }} </p>
<p>开发者账户已使用设备数: {{ option.developer_used_number }}</p>
<p>开发者账户可用设备数: {{ 100 - option.developer_used_number }}</p>
@ -42,7 +43,11 @@
<p>描述: {{ option.description }}</p>
<div slot="reference" class="name-wrapper">
<div>{{ option.issuer_id }} - {{
<div>
<el-tag v-if="option.app_used_number>0 && choices_data.indexOf(option.issuer_id)===-1 " size="mini"
type="warning"> Del
</el-tag>
{{ option.issuer_id }} - {{
option.usable_number - option.developer_used_number > 0
? option.usable_number - option.developer_used_number : 0
}} - {{ option.description }}
@ -63,9 +68,10 @@
<p>使用数量: {{ option.app_used_number }}</p>
<p>描述: {{ option.description }}</p>
<div slot="reference" class="name-wrapper">
<div><span v-if="option.app_usable_number>0">{{ option.app_usable_number }} - </span> {{ option.name }}
-
{{ option.bundle_id }} - {{ option.app_id }}
<div>
<span v-if="option.app_usable_number>0">{{ option.app_usable_number }} - </span>
<el-tag v-else-if="option.app_used_number>0" size="mini" type="warning"> Del</el-tag>
{{ option.name }} - {{ option.bundle_id }} - {{ option.app_id }}
</div>
</div>
</el-popover>
@ -113,7 +119,8 @@ export default {
s_props: {},
s_titles: [],
app_private_used_number: 100,
loadings: false
loadings: false,
app_limit_number: 0
};
},
mounted() {
@ -137,16 +144,36 @@ export default {
}
return [n_data, this.app_private_used_number]
},
handleChange(value,) {
handleChange(value, direction, movedKeys) {
if (this.issuer_id && direction === 'right') {
// if(value.length > this.app_limit_number){
// this.$message.warning(','+this.app_limit_number+'')
for (let i = 0; i < movedKeys.length; i++) {
let app_info = this.get_choice_data_from_key([movedKeys[i]])[0][0]
if (!(app_info && app_info.app_used_number > 0)) {
this.choices_data.splice(this.choices_data.indexOf(movedKeys[i]), 1)
}
}
// }
}
if (this.app_id && direction === 'right') {
for (let i = 0; i < movedKeys.length; i++) {
let developer_info = this.get_choice_data_from_key([movedKeys[i]])[0][0]
if (!(developer_info && developer_info.app_used_count)) {
this.choices_data.splice(this.choices_data.indexOf(movedKeys[i]), 1)
}
}
}
this.get_choice_data_from_key(value)
},
saveNumber(infos) {
check_used_number() {
if (this.get_choice_data_from_key(this.choices_data)[1] > 100) {
this.$message.warning("超出最大分配额度,请注意,尽量保证所有应用分配额度总和为 100")
}
},
saveNumber(infos) {
developerBindAppFun(data => {
if (data.code === 1000) {
// this.$message.success("")
// this.choices_data = this.format_data(data.data)
} else {
this.$message.error("数据更新失败" + data.msg)
@ -163,8 +190,11 @@ export default {
key: 'app_id',
label: 'name',
}
this.s_titles = ['可分配苹果应用', '已分配苹果应用']
this.getBindInfo({act: 'apps'})
// eslint-disable-next-line no-unused-vars
setTimeout(_ => {
this.check_used_number()
}, 1000)
} else {
this.s_props = {
key: 'issuer_id',
@ -179,8 +209,7 @@ export default {
saveAppleApps() {
developerBindAppFun(data => {
if (data.code === 1000) {
// this.$message.success("")
// this.choices_data = this.format_data(data.data)
this.$message.success("数据保存成功")
} else {
this.$message.error("数据更新失败" + data.msg)
}
@ -205,6 +234,12 @@ export default {
if (params.act === 'developer') {
this.app_developer_lists.sort(sort_compare('developer_used_number'))
}
if (params.act === 'apps') {
if (data.app_limit_number) {
this.app_limit_number = data.app_limit_number
}
this.s_titles = ['可分配苹果应用', '已分配苹果应用,最多可以分配' + this.app_limit_number + '个应用']
}
this.get_choice_data_from_key(this.choices_data)
} else {
this.choices_data_list = data.data;
@ -231,9 +266,6 @@ export default {
}
return n_data
},
format_data_number() {
},
}
}
</script>

@ -56,7 +56,16 @@
</div>
<el-form-item label="设备数量" label-width="110px" style="text-align: left">
<el-input-number v-model="editdeveloperinfo.usable_number" :max="100" :min="0" label="设备数量"/>
<el-input-number v-model="editdeveloperinfo.usable_number" :max="100" :min="0" label="设备数量" size="small"/>
<el-tag style="margin-left: 10px" type="warning">可消耗设备数量超过该数量将无法进行新设备签名已经消耗
{{ editdeveloperinfo.developer_used_number }} 个设备
</el-tag>
</el-form-item>
<el-form-item label="应用数量" label-width="110px" style="text-align: left">
<el-input-number v-model="editdeveloperinfo.app_limit_number" :max="160" :min="0" label="应用数量" size="small"/>
<el-tag style="margin-left: 10px" type="warning">可签名应用数量超过该数量将无法进行新应用签名已经分配
{{ editdeveloperinfo.app_used_count }} 个应用
</el-tag>
</el-form-item>
<el-form-item label="证书id" label-width="110px">
<el-input v-model="editdeveloperinfo.certid" :disabled='isedit'/>
@ -187,7 +196,7 @@
<el-input
v-model="appidseach"
clearable
placeholder="输入开发者ID"
placeholder="输入开发者ID或应用BundleID"
style="width: 27%;margin-right: 10px;margin-bottom: 10px"/>
<el-select v-model="developer_choice" clearable placeholder="账户类型"
@ -337,6 +346,8 @@
<el-popover placement="top" trigger="hover">
<p>签名了 {{ scope.row.app_used_count }} 个应用</p>
<p>应用限额 {{ scope.row.app_limit_number }} 个应用</p>
<p>还可以签名 {{ scope.row.app_limit_number - scope.row.app_used_count }} 个新应用</p>
<div slot="reference" class="name-wrapper">
<el-link v-if="scope.row.app_used_count > 0" :underline="false"
@click="show_device_ubill(scope.row.issuer_id)">
@ -363,7 +374,9 @@
@click="bindAppletoapp(scope.row)">
<el-tag size="medium"></el-tag>
</el-link>
<el-tag v-else size="medium" type="info" @click="bindAppletoapp(scope.row)"></el-tag>
<el-link v-else :underline="false" @click="bindAppletoapp(scope.row)">
<el-tag size="medium" type="info"></el-tag>
</el-link>
</div>
</el-popover>
</template>
@ -432,6 +445,11 @@
<el-form-item label="设备数量" label-width="110px" style="text-align: left">
<el-input-number v-model="editdeveloperinfo.usable_number" :max="100" :min="0" label="设备数量"/>
<el-tag style="margin-left: 10px" type="warning">该开发者可以可消耗设备数量超过该数量将无法进行新设备签名</el-tag>
</el-form-item>
<el-form-item label="应用数量" label-width="110px" style="text-align: left">
<el-input-number v-model="editdeveloperinfo.app_limit_number" :max="160" :min="0" label="应用数量"/>
<el-tag style="margin-left: 10px" type="warning">该开发者可以签名应用数量超过该数量将无法进行新应用签名</el-tag>
</el-form-item>
<el-form-item label="备注" label-width="110px">
@ -593,6 +611,14 @@
label="应用名称"
prop="bundle_name"
width="160">
<template slot-scope="scope">
<el-popover placement="top" trigger="hover">
<p>点击下载签名后的应用包</p>
<div slot="reference" class="name-wrapper">
<el-link :underline="false" @click="downloadipa(scope.row)">{{ scope.row.bundle_name }}</el-link>
</div>
</el-popover>
</template>
</el-table-column>
<el-table-column
align="center"
@ -950,7 +976,7 @@ export default {
dialogaddDeveloperVisible: false,
importcertDeveloperVisible: false,
title: "",
editdeveloperinfo: {auth_type: 0, usable_number: 100},
editdeveloperinfo: {auth_type: 0, usable_number: 100, app_limit_number: 100},
isedit: false,
placeholder: "",
pagination: {"currentPage": 1, "total": 0, "pagesize": 10},
@ -1017,6 +1043,19 @@ export default {
}
},
methods: {
downloadipa(info) {
this.loading = true;
iosdevices(data => {
if (data.code === 1000 && data.data && data.data.download_url) {
window.location.href = data.data.download_url;
} else {
this.$message.error(data.msg);
}
this.loading = false;
}, {
"methods": "POST", "data": info
})
},
copy_success() {
this.$message.success('复制剪切板成功');
},
@ -1219,7 +1258,7 @@ export default {
},
canceledit() {
this.dialogaddDeveloperVisible = false;
this.editdeveloperinfo = {auth_type: 0, usable_number: 100};
this.editdeveloperinfo = {auth_type: 0, usable_number: 100, app_limit_number: 100};
this.isedit = false;
this.placeholder = ""
},
@ -1366,12 +1405,12 @@ export default {
this.canceledit();
this.$message.success("操作成功");
this.activeName = "iosdeveloper";
this.editdeveloperinfo = {auth_type: 0, usable_number: 100};
this.editdeveloperinfo = {auth_type: 0, usable_number: 100, app_limit_number: 100};
}
if (!this.edit && this.editdeveloperinfo.issuer_id) {
this.$message.success("添加成功");
this.activeName = "iosdeveloper";
this.editdeveloperinfo = {auth_type: 0, usable_number: 100};
this.editdeveloperinfo = {auth_type: 0, usable_number: 100, app_limit_number: 100};
}
} else if (data.code === 1008) {
this.$message.error(data.msg);
@ -1506,9 +1545,13 @@ export default {
if (activeName_list[index] === activeName) {
this.activeName = activeName;
let bundleid = this.$route.query.bundleid;
let appidseach = this.$route.query.appidseach;
if (bundleid) {
this.Bundleidsearch = bundleid;
}
if (appidseach) {
this.appidseach = appidseach;
}
this.get_data_from_tabname(activeName);
return
}

@ -82,7 +82,7 @@ if (page) {
}
}
const version='1.3.6';
const version='1.3.7';
const pro_base_env = {
baseUrl: 'https://flyapps.cn',

@ -0,0 +1,17 @@
# Generated by Django 3.2.3 on 2021-12-16 10:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0026_appledevelopertoappuse'),
]
operations = [
migrations.AddField(
model_name='appiosdeveloperinfo',
name='app_limit_number',
field=models.IntegerField(default=100, verbose_name='可分配应用数,最大160'),
),
]

@ -273,6 +273,7 @@ class AppIOSDeveloperInfo(models.Model):
is_actived = models.BooleanField(default=False, verbose_name="是否已经激活")
certid = models.CharField(max_length=64, blank=True, verbose_name="超级签名自动创建证书ID", null=True)
usable_number = models.IntegerField(verbose_name="可使用设备数", default=100)
app_limit_number = models.IntegerField(verbose_name="可分配应用数,最大160", default=100)
created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
updated_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
cert_expire_time = models.DateTimeField(blank=True, null=True, verbose_name="证书过期时间")
@ -290,6 +291,12 @@ class AppIOSDeveloperInfo(models.Model):
self.usable_number = 100
elif self.usable_number < 0:
self.usable_number = 0
if self.app_limit_number > 160:
self.app_limit_number = 160
elif self.app_limit_number < 0:
self.app_limit_number = 0
return super(AppIOSDeveloperInfo, self).save(*args, **kwargs)
def __str__(self):

@ -13,7 +13,7 @@ from functools import wraps
import xmltodict
from django.core.cache import cache
from django.db.models import Count
from django.db.models import Count, F
from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo, Apps, APPToDeveloper, \
UDIDsyncDeveloper, DeveloperAppID, DeveloperDevicesID, IosDeveloperPublicPoolBill, UserInfo, AppleDeveloperToAppUse
@ -284,26 +284,33 @@ def get_new_developer_by_app_obj(user_objs, app_obj, apple_to_app=False):
used_number = get_developer_udided(developer_obj)[2] + get_developer_can_used_from_public_sign(
developer_obj.user_id)
if used_number < developer_obj.usable_number:
app_used_number = DeveloperDevicesID.objects.filter(developerid=developer_obj)
if apple_to_app:
apple_to_app_obj = AppleDeveloperToAppUse.objects.filter(app_id=app_obj,
developerid=developer_obj).first()
if apple_to_app_obj:
# 通过配置的专属分配数量进行过滤
app_used_number = DeveloperDevicesID.objects.filter(developerid=developer_obj,
app_id=app_obj).distinct().count()
if app_used_number < apple_to_app_obj.usable_number:
if app_used_number.filter(app_id=app_obj).distinct().count() < apple_to_app_obj.usable_number:
can_used_developer_pk_list.append(developer_obj.pk)
else:
if app_used_number.distinct().count() < developer_obj.app_limit_number:
can_used_developer_pk_list.append(developer_obj.pk)
return can_used_developer_pk_list
def get_developer_by_pk_list(developer_pk_list, f_key):
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,
is_actived=True,
certid__isnull=False).values(
f_key, 'pk').annotate(
count=Count('pk')).order_by('created_time').order_by('count').first()
f_key, 'pk').annotate(count=Count('pk'))
if not app_search_flag:
developer_obj_dict = developer_obj_dict.filter(count__lt=F('app_limit_number'))
return developer_obj_dict
def get_developer_by_pk_list(developer_pk_list, f_key, app_search_flag=True):
developer_obj_dict = filter_developer_by_pk_list(developer_pk_list, f_key, app_search_flag)
developer_obj_dict = developer_obj_dict.order_by('created_time').order_by('count').first()
if developer_obj_dict:
developer_obj = AppIOSDeveloperInfo.objects.filter(pk=developer_obj_dict.get('pk')).first()
logger.info(f'get {f_key} suitable developer {developer_obj} and return')
@ -332,8 +339,11 @@ def get_developer_user_by_app_udid(user_objs, udid, app_obj, private_first=True)
app_search_flag = False
developer_pk_list = developer_udid_queryset.filter(udid=udid)
# 若根据udid查找开发者账户,则通过应用签名数量进行过滤开发者账户,对应用已经存在开发者,则无需过滤
# 即使udid已经存在某个开发者,但是签名数量限制,也会将该udid注册到新的开发者,虽然会浪费设备数,但是也许是为了安全???!!!
# 苹果开发者的 bundleId 具体多大限制是未知的,因此定义了 app_limit_number 字段,最大值为160(该数值是理论估计值,具体可修改)
if developer_pk_list:
developer_obj = get_developer_by_pk_list(developer_pk_list, 'developerappid')
developer_obj = get_developer_by_pk_list(developer_pk_list, 'developerappid', app_search_flag)
if developer_obj:
if app_search_flag:
logger.info(f'udid:{udid} and app_obj:{app_obj} exist and return. developer_obj: {developer_obj}')
@ -348,6 +358,8 @@ def get_developer_user_by_app_udid(user_objs, udid, app_obj, private_first=True)
exist_app_developer_pk_list = []
developer_pk_list = developer_udid_queryset.filter(developerid__apptodeveloper__app_id=app_obj)
if developer_pk_list:
# developer_obj_dict_queryset = filter_developer_by_pk_list(developer_pk_list, 'developerappid')
# developer_pk_list = [developer_obj_dict.get('pk') for developer_obj_dict in developer_obj_dict_queryset]
for developer_obj in AppIOSDeveloperInfo.objects.filter(pk__in=developer_pk_list):
if get_developer_udided(developer_obj)[2] + get_developer_can_used_from_public_sign(
developer_obj.user_id) < developer_obj.usable_number:
@ -359,7 +371,7 @@ def get_developer_user_by_app_udid(user_objs, udid, app_obj, private_first=True)
# 存在专属开发者账户,但是也同时存在已经安装的设备,优先选择已经安装设备的开发者账户?是or否
# 是:使应用趋向于一个开发者,为后期更新提供方便
# 否:优先使用专属开发者进行签名
# 否:优先使用专属开发者进行签名,默认值为否,则专属优先
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

@ -180,6 +180,11 @@ class AppsSerializer(serializers.ModelSerializer):
def get_supersign_used_number(self, obj):
return models.APPSuperSignUsedInfo.objects.filter(app_id=obj).all().count()
developer_used_count = serializers.SerializerMethodField()
def get_developer_used_count(self, obj):
return models.DeveloperAppID.objects.filter(app_id=obj).all().count()
screenshots = serializers.SerializerMethodField()
def get_screenshots(self, obj):
@ -493,7 +498,17 @@ class DeveloperSerializer(serializers.ModelSerializer):
return get_developer_udided(obj)[0]
def get_is_disabled(self, obj):
return bool(1 - obj.is_actived)
app_id = self.context.get('app_id', '')
if app_id:
developer_app_obj = models.DeveloperAppID.objects.filter(developerid=obj, developerid__is_actived=True,
developerid__certid__isnull=False)
if developer_app_obj.filter(app_id__app_id=app_id).distinct().count():
return False
else:
if developer_app_obj and developer_app_obj.distinct().count() < obj.app_limit_number:
return False
return True
return True
def get_app_private_number(self, obj):
return models.AppleDeveloperToAppUse.objects.filter(developerid=obj).count()

@ -14,8 +14,9 @@ from django.utils import timezone
from api.models import Apps, UserInfo, AppReleaseInfo, AppUDID, APPToDeveloper, APPSuperSignUsedInfo, \
UserCertificationInfo, Order
from api.utils.baseutils import check_app_password, get_order_num
from api.utils.modelutils import get_app_d_count_by_app_id, get_app_domain_name, get_user_domain_name
from api.utils.baseutils import check_app_password, get_order_num, get_real_ip_address
from api.utils.modelutils import get_app_d_count_by_app_id, get_app_domain_name, get_user_domain_name, \
add_remote_info_from_request
from api.utils.storage.storage import Storage, LocalStorage
from fir_ser.settings import CACHE_KEY_TEMPLATE, SERVER_DOMAIN, SYNC_CACHE_TO_DATABASE, DEFAULT_MOBILEPROVISION, \
USER_FREE_DOWNLOAD_TIMES, AUTH_USER_FREE_DOWNLOAD_TIMES
@ -602,3 +603,45 @@ def get_and_clean_udid_cache_queue(prefix_key):
data = []
cache.delete(prefix_key)
return data
def get_app_download_url(request, res, app_id, short, password, release_id, isdownload, udid):
app_obj = get_app_instance_by_cache(app_id, password, 900, udid)
if app_obj:
if app_obj.get("type") == 0:
app_type = '.apk'
download_url, extra_url = get_download_url_by_cache(app_obj, release_id + app_type, 600)
else:
app_type = '.ipa'
if isdownload:
download_url, extra_url = get_download_url_by_cache(app_obj, release_id + app_type, 600,
udid=udid)
else:
download_url, extra_url = get_download_url_by_cache(app_obj, release_id + app_type, 600,
isdownload,
udid=udid)
res.data = {"download_url": download_url, "extra_url": extra_url}
if download_url != "" and "mobileconifg" not in download_url:
ip = get_real_ip_address(request)
msg = f"remote ip {ip} short {short} download_url {download_url} app_obj {app_obj}"
logger.info(msg)
add_remote_info_from_request(request, msg)
set_app_download_by_cache(app_id)
amount = app_obj.get("d_count")
# # 超级签需要多消耗2倍下载次数
# if app_obj.get("issupersign"):
# amount *= 2
auth_status = False
status = app_obj.get('user_id__certification__status', None)
if status and status == 1:
auth_status = True
if not consume_user_download_times(app_obj.get("user_id"), app_id, amount, auth_status):
res.code = 1009
res.msg = "可用下载额度不足"
del res.data
return res
return res
res.code = 1006
res.msg = "该应用不存在"
return res

@ -15,15 +15,14 @@ from api.models import Apps, AppReleaseInfo, APPToDeveloper, APPSuperSignUsedInf
from api.utils.TokenManager import verify_token
from api.utils.app.apputils import make_resigned
from api.utils.app.supersignutils import make_sign_udid_mobile_config
from api.utils.baseutils import get_profile_full_path, make_random_uuid, get_real_ip_address, get_origin_domain_name, \
from api.utils.baseutils import get_profile_full_path, make_random_uuid, get_origin_domain_name, \
format_get_uri, get_post_udid_url
from api.utils.decorators import cache_response # 本来使用的是 drf-extensions==0.7.0 但是还未支持该版本Django
from api.utils.modelutils import get_app_domain_name, get_filename_form_file, check_app_domain_name_access, \
ad_random_weight, get_redirect_server_domain, add_remote_info_from_request
ad_random_weight, get_redirect_server_domain
from api.utils.response import BaseResponse
from api.utils.serializer import AppsShortSerializer, AppAdInfoSerializer
from api.utils.storage.caches import get_app_instance_by_cache, get_download_url_by_cache, set_app_download_by_cache, \
del_cache_response_by_short, consume_user_download_times, check_app_permission
from api.utils.storage.caches import del_cache_response_by_short, check_app_permission, get_app_download_url
from api.utils.storage.storage import Storage, get_local_storage
from api.utils.throttle import VisitShortThrottle, InstallShortThrottle, InstallThrottle1, InstallThrottle2
from fir_ser import settings
@ -230,47 +229,8 @@ class InstallView(APIView):
return Response(res.dict)
if verify_token(downtoken, release_id):
app_obj = get_app_instance_by_cache(app_id, password, 900, udid)
if app_obj:
if app_obj.get("type") == 0:
app_type = '.apk'
download_url, extra_url = get_download_url_by_cache(app_obj, release_id + app_type, 600)
else:
app_type = '.ipa'
if isdownload:
download_url, extra_url = get_download_url_by_cache(app_obj, release_id + app_type, 600,
udid=udid)
else:
download_url, extra_url = get_download_url_by_cache(app_obj, release_id + app_type, 600,
isdownload,
udid=udid)
res.data = {"download_url": download_url, "extra_url": extra_url}
if download_url != "" and "mobileconifg" not in download_url:
ip = get_real_ip_address(request)
msg = f"remote ip {ip} short {short} download_url {download_url} app_obj {app_obj}"
logger.info(msg)
add_remote_info_from_request(request, msg)
set_app_download_by_cache(app_id)
amount = app_obj.get("d_count")
# # 超级签需要多消耗2倍下载次数
# if app_obj.get("issupersign"):
# amount *= 2
auth_status = False
status = app_obj.get('user_id__certification__status', None)
if status and status == 1:
auth_status = True
if not consume_user_download_times(app_obj.get("user_id"), app_id, amount, auth_status):
res.code = 1009
res.msg = "可用下载额度不足"
del res.data
return Response(res.dict)
return Response(res.dict)
res = get_app_download_url(request, res, app_id, short, password, release_id, isdownload, udid)
else:
res.code = 1004
res.msg = "token校验失败"
return Response(res.dict)
res.code = 1006
res.msg = "该应用不存在"
return Response(res.dict)

@ -13,14 +13,14 @@ from rest_framework.response import Response
from rest_framework.views import APIView
from api.models import AppIOSDeveloperInfo, APPSuperSignUsedInfo, AppUDID, IosDeveloperPublicPoolBill, \
UDIDsyncDeveloper, AppleDeveloperToAppUse, Apps
UDIDsyncDeveloper, AppleDeveloperToAppUse, Apps, DeveloperAppID, APPToDeveloper
from api.utils.app.supersignutils import IosUtils
from api.utils.auth import ExpiringTokenAuthentication, SuperSignPermission
from api.utils.modelutils import get_user_public_used_sign_num, get_user_public_sign_num
from api.utils.response import BaseResponse
from api.utils.serializer import DeveloperSerializer, SuperSignUsedSerializer, DeviceUDIDSerializer, BillInfoSerializer, \
DeveloperDeviceSerializer, AppleDeveloperToAppUseSerializer, AppleDeveloperToAppUseAppsSerializer
from api.utils.storage.caches import CleanSignDataState
from api.utils.storage.caches import CleanSignDataState, get_app_download_url
from api.utils.utils import get_developer_devices, get_choices_dict
logger = logging.getLogger(__name__)
@ -50,7 +50,9 @@ class DeveloperView(APIView):
developer_obj = developer_obj.distinct()
res.use_num = get_developer_devices(developer_obj)
if issuer_id:
developer_obj = developer_obj.filter(issuer_id=issuer_id)
developer_obj = developer_obj.filter(
Q(developerappid__app_id__bundle_id=issuer_id, developerappid__app_id__user_id=request.user) | Q(
issuer_id=issuer_id))
page_obj = PageNumber()
app_page_serializer = page_obj.paginate_queryset(queryset=developer_obj.order_by("-updated_time"),
@ -154,12 +156,17 @@ class DeveloperView(APIView):
f"user {request.user} ios developer {developer_obj} update old data {developer_obj.__dict__}")
try:
usable_number = int(data.get("usable_number", developer_obj.usable_number))
app_limit_number = int(data.get("app_limit_number", developer_obj.app_limit_number))
if 0 <= usable_number <= 100:
developer_obj.usable_number = usable_number
update_fields.append("usable_number")
if 0 <= app_limit_number <= 160:
developer_obj.app_limit_number = app_limit_number
update_fields.append("app_limit_number")
except Exception as e:
logger.error(
f"developer {developer_obj} usable_number {data.get('usable_number', developer_obj.usable_number)} get failed Exception:{e}")
developer_obj.description = data.get("description", developer_obj.description)
update_fields.append("description")
private_key_id = data.get("private_key_id", developer_obj.private_key_id)
@ -260,6 +267,21 @@ class SuperSignUsedView(APIView):
res.count = super_sign_used_objs.count()
return Response(res.dict)
def post(self, request):
res = BaseResponse()
data = request.data
device_udid = data.get('device_udid', '')
developer_id = data.get('developer_id', '')
bundle_id = data.get('bundle_id', '')
if device_udid and developer_id and bundle_id:
app_obj = Apps.objects.filter(user_id=request.user, bundle_id=bundle_id).first()
app_to_dev_obj = APPToDeveloper.objects.filter(app_id=app_obj, developerid__issuer_id=developer_id).first()
if app_obj and app_to_dev_obj:
res = get_app_download_url(request, res, app_obj.app_id, app_obj.short, app_obj.password,
app_to_dev_obj.binary_file, True, device_udid)
return Response(res.dict)
class AppUDIDUsedView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ]
@ -473,9 +495,14 @@ class AppleDeveloperBindAppsView(APIView):
issuer_id = request.query_params.get("issuer_id", '')
app_id = request.query_params.get("app_id", '')
if act == 'apps':
res.app_limit_number = 0
apps_obj_list = Apps.objects.filter(user_id=request.user, type=1).all()
app_serializer = AppleDeveloperToAppUseAppsSerializer(apps_obj_list, many=True,
context={'issuer_id': issuer_id})
if issuer_id:
developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=request.user, issuer_id=issuer_id).first()
if developer_obj:
res.app_limit_number = developer_obj.app_limit_number
elif act == 'developer':
developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=request.user).all()
app_serializer = DeveloperSerializer(developer_obj, many=True, context={'app_id': app_id})
@ -508,8 +535,18 @@ class AppleDeveloperBindAppsView(APIView):
remove_issuer_ids = list(set(issuer_id_list) - set(choices_data))
for item in add_issuer_ids:
developer_obj = AppIOSDeveloperInfo.objects.filter(issuer_id=item, user_id=request.user).first()
developer_obj = AppIOSDeveloperInfo.objects.filter(issuer_id=item, user_id=request.user,
is_actived=True, certid__isnull=False).first()
developer_aid_obj = DeveloperAppID.objects.filter(developerid=developer_obj)
is_exist = developer_aid_obj.filter(app_id=app_obj).count()
if developer_obj:
app_flag = False
if is_exist:
app_flag = True
else:
if developer_aid_obj.count() < developer_obj.app_limit_number:
app_flag = True
if app_flag:
many_obj.append(AppleDeveloperToAppUse(developerid=developer_obj, app_id=app_obj))
AppleDeveloperToAppUse.objects.filter(developerid__issuer_id__in=remove_issuer_ids, app_id=app_obj).delete()
@ -522,10 +559,23 @@ class AppleDeveloperBindAppsView(APIView):
add_app_ids = list(set(choices_data) - set(app_id_list))
remove_app_ids = list(set(app_id_list) - set(choices_data))
exist_app_id_queryset = DeveloperAppID.objects.filter(developerid=developer_obj).values(
'app_id__app_id').all()
exist_app_ids = [exist_app_id_obj.get('app_id__app_id') for exist_app_id_obj in exist_app_id_queryset]
can_add_number = developer_obj.app_limit_number - len(exist_app_ids)
for item in add_app_ids:
app_obj = Apps.objects.filter(app_id=item, type=1, user_id=request.user).first()
if app_obj:
app_flag = False
if item in exist_app_ids:
app_flag = True
else:
if can_add_number > 0:
can_add_number -= 1
app_flag = True
if app_flag:
many_obj.append(AppleDeveloperToAppUse(developerid=developer_obj, app_id=app_obj))
AppleDeveloperToAppUse.objects.filter(developerid=developer_obj, app_id__app_id__in=remove_app_ids,
app_id__user_id=request.user).delete()

Loading…
Cancel
Save