修改文件下载失败问题

增加签名不足跳转功能
限制24小时只能发送6次通知
dependabot/npm_and_yarn/fir_admin/async-2.6.4
nineven 3 years ago
parent 6c25f6a932
commit 58472fb9e4
  1. 32
      fir_client/src/components/FirDownload.vue
  2. 32
      fir_client/src/components/ShortDownload.vue
  3. 28
      fir_client/src/components/apps/FirAppInfossupersign.vue
  4. 2
      fir_client/src/components/user/FirSuperSignBase.vue
  5. 13
      fir_ser/api/migrations/0001_initial.py
  6. 9
      fir_ser/api/migrations/0005_auto_20220412_1744.py
  7. 12
      fir_ser/api/models.py
  8. 1
      fir_ser/api/views/personalconfig.py
  9. 35
      fir_ser/common/base/magic.py
  10. 4
      fir_ser/common/core/sysconfig.py
  11. 9
      fir_ser/common/notify/notify.py
  12. 2
      fir_ser/common/utils/download.py
  13. 4
      fir_ser/config.py
  14. 35
      fir_ser/xsign/tasks.py
  15. 4
      fir_ser/xsign/utils/serializer.py
  16. 37
      fir_ser/xsign/utils/supersignutils.py
  17. 7
      fir_ser/xsign/views/appinfo.py
  18. 11
      fir_ser/xsign/views/receiveudids.py

@ -561,12 +561,18 @@ export default {
} }
if (data.code === 1000) { if (data.code === 1000) {
window.clearInterval(loop_t); window.clearInterval(loop_t);
if (data.msg) { if (data.data) {
this.show_err_msg(data.msg); if (data.data.code === 1000) {
} else {
this.$message.success('签名完成,请点击下载安装'); this.$message.success('签名完成,请点击下载安装');
this.wrong = false; this.wrong = false;
this.binary_download(); this.binary_download();
} else {
if (data.data.redirect) {
window.location.href = data.data.redirect
} else if (data.data.msg) {
this.show_err_msg(data.data.msg);
}
}
} }
} else { } else {
if (data.code === 1002) { if (data.code === 1002) {
@ -635,15 +641,21 @@ export default {
this.msg = '签名处理中,请耐心等待'; this.msg = '签名处理中,请耐心等待';
gettask(data => { gettask(data => {
if (data.code === 1000) { if (data.code === 1000) {
if (data.task_id) { if (data.data) {
this.$route.query.task_id = data.task_id; if (data.data.code === 1000) {
this.loop_check_task()
} else if (data.result) {
this.show_err_msg(data.result);
} else {
this.wrong = false; this.wrong = false;
this.currentappinfo.need_password = false this.currentappinfo.need_password = false
this.binary_download() this.binary_download()
} else {
if (data.data.redirect) {
window.location.href = data.data.redirect
} else if (data.data.msg) {
this.show_err_msg(data.data.msg);
}
}
} else if (data.task_id) {
this.$route.query.task_id = data.task_id;
this.loop_check_task()
} }
} else if (data.code === 1006) { } else if (data.code === 1006) {
this.msg = data.msg; this.msg = data.msg;
@ -652,7 +664,7 @@ export default {
this.err_password = true this.err_password = true
this.currentappinfo.need_password = true this.currentappinfo.need_password = true
this.password = '' this.password = ''
} else if (data.code === 1007) { } else if (data.code === 1005) {
this.msg = data.msg; this.msg = data.msg;
this.show_err_msg(data.msg); this.show_err_msg(data.msg);
this.wrong = true; this.wrong = true;

@ -527,11 +527,17 @@ export default {
} }
if (data.code === 1000) { if (data.code === 1000) {
window.clearInterval(loop_t); window.clearInterval(loop_t);
if (data.msg) { if (data.data) {
this.show_err_msg(data.msg); if (data.data.code === 1000) {
} else {
this.wrong = false; this.wrong = false;
this.binary_download(); this.binary_download();
} else {
if (data.data.redirect) {
window.location.href = data.data.redirect
} else if (data.data.msg) {
this.show_err_msg(data.data.msg);
}
}
} }
} else { } else {
if (data.code === 1002) { if (data.code === 1002) {
@ -600,15 +606,21 @@ export default {
this.msg = '签名处理中,请耐心等待'; this.msg = '签名处理中,请耐心等待';
gettask(data => { gettask(data => {
if (data.code === 1000) { if (data.code === 1000) {
if (data.task_id) { if (data.data) {
this.$route.query.task_id = data.task_id; if (data.data.code === 1000) {
this.loop_check_task()
} else if (data.result) {
this.show_err_msg(data.result);
} else {
this.wrong = false; this.wrong = false;
this.currentappinfo.need_password = false this.currentappinfo.need_password = false
this.binary_download() this.binary_download()
} else {
if (data.data.redirect) {
window.location.href = data.data.redirect
} else if (data.data.msg) {
this.show_err_msg(data.data.msg);
}
}
} else if (data.task_id) {
this.$route.query.task_id = data.task_id;
this.loop_check_task()
} }
} else if (data.code === 1006) { } else if (data.code === 1006) {
this.msg = data.msg; this.msg = data.msg;
@ -617,7 +629,7 @@ export default {
this.err_password = true; this.err_password = true;
this.currentappinfo.need_password = true; this.currentappinfo.need_password = true;
this.password = '' this.password = ''
} else if (data.code === 1007) { } else if (data.code === 1005) {
this.msg = data.msg; this.msg = data.msg;
this.show_err_msg(data.msg); this.show_err_msg(data.msg);
this.wrong = true; this.wrong = true;

@ -114,6 +114,34 @@
>保存 >保存
</el-button> </el-button>
</el-form-item> </el-form-item>
<el-divider/>
<el-form-item label="设备异常等待跳转"
label-width="200px">
<el-switch
v-model="currentapp.abnormal_redirect"
:active-value="true"
:disabled="supersign_disable"
:inactive-value="false"
active-color="#13ce66"
inactive-color="#ff4949"
@change="saveappinfo({abnormal_redirect:currentapp.abnormal_redirect})">
</el-switch>
<el-link :underline="false" style="margin-left: 20px">该配置仅当开启异常设备注册等待有效若启用该配置根据规则会自动跳转链接</el-link>
</el-form-item>
<el-divider/>
<el-form-item label="签名不足跳转链接" label-width="200px">
<el-input v-model="currentapp.supersign_redirect_url" :disabled="supersign_disable"
clearable prefix-icon="el-icon-s-promotion"
style="width: 60%;margin-right: 10px"/>
<el-button :disabled="supersign_disable"
@click="saveappinfo({supersign_redirect_url:currentapp.supersign_redirect_url})"
>保存
</el-button>
<el-link :underline="false">当设备余额不足无法进行签名可配置该链接跳转到第三方下载平台</el-link>
</el-form-item>
<el-divider/>
</el-form> </el-form>
<el-link v-else :underline="false" type="warning"> 该用户暂未开通超级签权限,请联系管理员申请开通</el-link> <el-link v-else :underline="false" type="warning"> 该用户暂未开通超级签权限,请联系管理员申请开通</el-link>

@ -1149,7 +1149,7 @@
<p>开发者备注: {{ scope.row.developer_description }}</p> <p>开发者备注: {{ scope.row.developer_description }}</p>
<p>开发者状态: {{ scope.row.developer_status }}</p> <p>开发者状态: {{ scope.row.developer_status }}</p>
<p>安装异常??? <p>安装异常???
<el-button :disabled="scope.row.developer_status!=='已激活'" size="small" @click="resign(scope.row)"> <el-button :disabled="!scope.row.can_resign" size="small" @click="resign(scope.row)">
尝试重新签包 尝试重新签包
</el-button> </el-button>
</p> </p>

@ -74,8 +74,12 @@ class Migration(migrations.Migration):
('bundle_id', models.CharField(blank=True, max_length=64, verbose_name='bundle id')), ('bundle_id', models.CharField(blank=True, max_length=64, verbose_name='bundle id')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')), ('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('count_hits', models.BigIntegerField(default=0, verbose_name='下载次数')), ('count_hits', models.BigIntegerField(default=0, verbose_name='下载次数')),
('password', models.CharField(blank=True, help_text='默认 没有密码', max_length=32, verbose_name='访问密码')), ('need_password', models.BooleanField(default=False, help_text='默认 没有密码', verbose_name='访问密码')),
('isshow', models.BooleanField(default=True, verbose_name='下载页可见')), ('isshow', models.BooleanField(default=True, verbose_name='下载页可见')),
('wxredirect', models.BooleanField(default=True, verbose_name='微信内第三方链接自动跳转')),
('wxeasytype', models.BooleanField(default=True, verbose_name='微信内简易模式,避免微信封停')),
('description', models.TextField(blank=True, default=None, null=True, verbose_name='描述')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('issupersign', models.BooleanField(default=False, verbose_name='是否超级签名包')), ('issupersign', models.BooleanField(default=False, verbose_name='是否超级签名包')),
('change_auto_sign', models.BooleanField(default=False, verbose_name='签名相关的数据更新自动签名')), ('change_auto_sign', models.BooleanField(default=False, verbose_name='签名相关的数据更新自动签名')),
('supersign_type', models.SmallIntegerField( ('supersign_type', models.SmallIntegerField(
@ -86,10 +90,9 @@ class Migration(migrations.Migration):
('new_bundle_name', models.CharField(blank=True, help_text='应用新名称', max_length=64, null=True, ('new_bundle_name', models.CharField(blank=True, help_text='应用新名称', max_length=64, null=True,
verbose_name='new_bundle_name')), verbose_name='new_bundle_name')),
('supersign_limit_number', models.IntegerField(default=0, verbose_name='签名使用限额')), ('supersign_limit_number', models.IntegerField(default=0, verbose_name='签名使用限额')),
('wxredirect', models.BooleanField(default=True, verbose_name='微信内第三方链接自动跳转')), ('supersign_redirect_url',
('wxeasytype', models.BooleanField(default=True, verbose_name='微信内简易模式,避免微信封停')), models.CharField(blank=True, max_length=128, null=True, verbose_name='签名失败跳转第三方URL')),
('description', models.TextField(blank=True, default=None, null=True, verbose_name='描述')), ('abnormal_redirect', models.BooleanField(default=False, verbose_name='签名异常【一般为设备异常等待】跳转')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('has_combo', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, ('has_combo', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL,
related_name='combo_app_info', to='api.apps', verbose_name='关联应用')), related_name='combo_app_info', to='api.apps', verbose_name='关联应用')),
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, ('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL,

@ -11,15 +11,6 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RemoveField(
model_name='apps',
name='password',
),
migrations.AddField(
model_name='apps',
name='need_password',
field=models.BooleanField(default=False, help_text='默认 没有密码', verbose_name='访问密码'),
),
migrations.CreateModel( migrations.CreateModel(
name='AppDownloadToken', name='AppDownloadToken',
fields=[ fields=[

@ -155,6 +155,12 @@ class Apps(models.Model):
count_hits = models.BigIntegerField(verbose_name="下载次数", default=0) count_hits = models.BigIntegerField(verbose_name="下载次数", default=0)
need_password = models.BooleanField(verbose_name="访问密码", help_text='默认 没有密码', default=False) need_password = models.BooleanField(verbose_name="访问密码", help_text='默认 没有密码', default=False)
isshow = models.BooleanField(verbose_name="下载页可见", default=True) isshow = models.BooleanField(verbose_name="下载页可见", default=True)
wxredirect = models.BooleanField(verbose_name="微信内第三方链接自动跳转", default=True)
wxeasytype = models.BooleanField(verbose_name="微信内简易模式,避免微信封停", default=True)
description = models.TextField('描述', blank=True, null=True, default=None, )
updated_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
# 超级签名相关
issupersign = models.BooleanField(verbose_name="是否超级签名包", default=False) issupersign = models.BooleanField(verbose_name="是否超级签名包", default=False)
change_auto_sign = models.BooleanField(verbose_name="签名相关的数据更新自动签名", default=False) change_auto_sign = models.BooleanField(verbose_name="签名相关的数据更新自动签名", default=False)
supersign_type_choices = ((0, '普通权限'), (1, '推送权限,请上传adhoc包'), (2, 'network、vpn、推送权限,请上传adhoc包'), (3, '特殊权限')) supersign_type_choices = ((0, '普通权限'), (1, '推送权限,请上传adhoc包'), (2, 'network、vpn、推送权限,请上传adhoc包'), (3, '特殊权限'))
@ -164,10 +170,8 @@ class Apps(models.Model):
new_bundle_name = models.CharField(max_length=64, blank=True, null=True, verbose_name="new_bundle_name", new_bundle_name = models.CharField(max_length=64, blank=True, null=True, verbose_name="new_bundle_name",
help_text="应用新名称") help_text="应用新名称")
supersign_limit_number = models.IntegerField(verbose_name="签名使用限额", default=0) supersign_limit_number = models.IntegerField(verbose_name="签名使用限额", default=0)
wxredirect = models.BooleanField(verbose_name="微信内第三方链接自动跳转", default=True) supersign_redirect_url = models.CharField(max_length=128, blank=True, verbose_name="签名失败跳转第三方URL", null=True)
wxeasytype = models.BooleanField(verbose_name="微信内简易模式,避免微信封停", default=True) abnormal_redirect = models.BooleanField(verbose_name="签名异常【一般为设备异常等待】跳转", default=False)
description = models.TextField('描述', blank=True, null=True, default=None, )
updated_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
class Meta: class Meta:
verbose_name = '应用信息' verbose_name = '应用信息'

@ -48,6 +48,7 @@ class PersonalConfigView(APIView):
config_value = request.data.get("config_value", None) config_value = request.data.get("config_value", None)
if config_key is not None and config_value is not None and config_key in Config.DEVELOPER_STATUS_CONFIG: if config_key is not None and config_value is not None and config_key in Config.DEVELOPER_STATUS_CONFIG:
UserPersonalConfig.objects.filter(user_id=request.user, key=config_key).update(value=config_value) UserPersonalConfig.objects.filter(user_id=request.user, key=config_key).update(value=config_value)
UserConfig(request.user).invalid_config_cache(config_key)
return Response(res.dict) return Response(res.dict)
def delete(self, request): def delete(self, request):

@ -134,3 +134,38 @@ def import_from_string(dotted_path):
return getattr(module, class_name) return getattr(module, class_name)
except AttributeError as err: except AttributeError as err:
raise ImportError(f'Module "{module_path}" does not define a "{class_name}" attribute/class') from err raise ImportError(f'Module "{module_path}" does not define a "{class_name}" attribute/class') from err
def magic_call_in_times(call_time=24 * 3600, call_limit=6, key=None):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
cache_key = func.__name__
if key:
cache_key = f'magic_call_in_times_{cache_key}_{key(*args, **kwargs)}'
cache_data = cache.get(cache_key)
if cache_data:
if cache_data > call_limit:
err_msg = f'{func} not yet started. cache_key:{cache_key} call over limit {call_limit} in {call_time}'
logger.warning(err_msg)
return False, err_msg
else:
cache.incr(cache_key, 1)
else:
cache.set(cache_key, 1, call_time)
start_time = time.time()
try:
res = func(*args, **kwargs)
logger.info(
f"exec {func} finished. time:{time.time() - start_time} cache_key:{cache_key} result:{res}")
status = True
except Exception as e:
res = str(e)
logger.info(f"exec {func} failed. time:{time.time() - start_time} cache_key:{cache_key} Exception:{e}")
status = False
return status, res
return wrapper
return decorator

@ -377,6 +377,10 @@ class AppleDeveloperConfCache(ConfigCacheBase):
def DEVELOPER_WAIT_ABNORMAL_STATE(self): def DEVELOPER_WAIT_ABNORMAL_STATE(self):
return super().get_value('DEVELOPER_WAIT_ABNORMAL_STATE', APPLEDEVELOPERCONF.DEVELOPER_WAIT_ABNORMAL_STATE) return super().get_value('DEVELOPER_WAIT_ABNORMAL_STATE', APPLEDEVELOPERCONF.DEVELOPER_WAIT_ABNORMAL_STATE)
@property
def DEVELOPER_RESIGN_STATUS(self):
return super().get_value('DEVELOPER_RESIGN_STATUS', APPLEDEVELOPERCONF.DEVELOPER_RESIGN_STATUS)
class UserPersonalConfKeyCache(ConfigCacheBase): class UserPersonalConfKeyCache(ConfigCacheBase):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

@ -8,6 +8,7 @@ import logging
from api.utils.modelutils import get_notify_wx_queryset, get_wx_nickname from api.utils.modelutils import get_notify_wx_queryset, get_wx_nickname
from common.base.baseutils import get_format_time from common.base.baseutils import get_format_time
from common.base.magic import magic_call_in_times
from common.libs.mp.wechat import WxTemplateMsg from common.libs.mp.wechat import WxTemplateMsg
from common.libs.sendmsg.template_content import get_pay_success_html_content, get_sign_failed_html_content, \ from common.libs.sendmsg.template_content import get_pay_success_html_content, get_sign_failed_html_content, \
get_sign_unavailable_developer_html_content, get_sign_app_over_limit_html_content, \ get_sign_unavailable_developer_html_content, get_sign_app_over_limit_html_content, \
@ -41,6 +42,11 @@ def pay_success_notify(user_obj, order_obj):
notify_by_email(user_obj, message_type, get_pay_success_html_content(user_obj, order_obj)) notify_by_email(user_obj, message_type, get_pay_success_html_content(user_obj, order_obj))
def get_magic_call_key(*args, **kwargs):
return args[0].uid
@magic_call_in_times(key=get_magic_call_key)
def sign_failed_notify(user_obj, developer_obj, app_obj): def sign_failed_notify(user_obj, developer_obj, app_obj):
""" """
3, '应用签名失败' 3, '应用签名失败'
@ -59,6 +65,7 @@ def sign_failed_notify(user_obj, developer_obj, app_obj):
notify_by_email(user_obj, message_type, get_sign_failed_html_content(user_obj, app_obj, developer_obj, now_time)) notify_by_email(user_obj, message_type, get_sign_failed_html_content(user_obj, app_obj, developer_obj, now_time))
@magic_call_in_times(key=get_magic_call_key)
def sign_unavailable_developer_notify(user_obj, app_obj): def sign_unavailable_developer_notify(user_obj, app_obj):
""" """
3, '应用签名失败' 3, '应用签名失败'
@ -75,6 +82,7 @@ def sign_unavailable_developer_notify(user_obj, app_obj):
notify_by_email(user_obj, message_type, get_sign_unavailable_developer_html_content(user_obj, app_obj, now_time)) notify_by_email(user_obj, message_type, get_sign_unavailable_developer_html_content(user_obj, app_obj, now_time))
@magic_call_in_times(key=get_magic_call_key)
def sign_app_over_limit_notify(user_obj, app_obj, used_num, limit_number): def sign_app_over_limit_notify(user_obj, app_obj, used_num, limit_number):
""" """
0, '签名余额不足' 0, '签名余额不足'
@ -123,6 +131,7 @@ def check_developer_status_notify(user_obj, developer_obj_list, developer_used_i
yesterday_used_number)) yesterday_used_number))
@magic_call_in_times(key=get_magic_call_key)
def download_times_not_enough(user_obj, msg): def download_times_not_enough(user_obj, msg):
""" """
1, '下载次数不足' 1, '下载次数不足'

@ -117,6 +117,8 @@ def get_app_download_url(request, res, app_id, short, password, release_id, is_d
app_type = '.ipa' app_type = '.ipa'
download_url, extra_url = get_download_url_by_cache(app_obj, release_id + app_type, 600, is_download, download_url, extra_url = get_download_url_by_cache(app_obj, release_id + app_type, 600, is_download,
udid=udid) udid=udid)
encrypt_password = ''
if password:
encrypt_password = AesBaseCrypt().get_encrypt_uid(password) encrypt_password = AesBaseCrypt().get_encrypt_uid(password)
res.data = {"download_url": download_url, "extra_url": extra_url, "password": encrypt_password} res.data = {"download_url": download_url, "extra_url": extra_url, "password": encrypt_password}
logger.info(f'app download url :{res.data}') logger.info(f'app download url :{res.data}')

@ -412,6 +412,10 @@ class APPLEDEVELOPERCONF(object):
DEVELOPER_DISABLED_STATUS = [AppleDeveloperStatus.AGREEMENT_NOT_AGREED, AppleDeveloperStatus.CERTIFICATE_EXPIRED, DEVELOPER_DISABLED_STATUS = [AppleDeveloperStatus.AGREEMENT_NOT_AGREED, AppleDeveloperStatus.CERTIFICATE_EXPIRED,
AppleDeveloperStatus.CERTIFICATE_MISSING, AppleDeveloperStatus.DEVICE_ABNORMAL] AppleDeveloperStatus.CERTIFICATE_MISSING, AppleDeveloperStatus.DEVICE_ABNORMAL]
# 重签状态
DEVELOPER_RESIGN_STATUS = [AppleDeveloperStatus.ACTIVATED, AppleDeveloperStatus.DEVICE_ABNORMAL,
AppleDeveloperStatus.MAINTENANCE]
""" """
DEVELOPER_WAIT_STATUS 开发者等待状态详情查看 model.AppIOSDeveloperInfo DEVELOPER_WAIT_ABNORMAL_STATE 状态有关 DEVELOPER_WAIT_STATUS 开发者等待状态详情查看 model.AppIOSDeveloperInfo DEVELOPER_WAIT_ABNORMAL_STATE 状态有关

@ -26,37 +26,46 @@ def run_sign_task(format_udid_info, short, client_ip):
user_obj = app_obj.user_id user_obj = app_obj.user_id
if MigrateStorageState(user_obj.uid).get_state(): if MigrateStorageState(user_obj.uid).get_state():
msg = "数据迁移中,无法处理该操作" msg = "数据迁移中,无法处理该操作"
return msg code = 1000
return {'code': code, 'msg': msg}
try: try:
ios_sign_obj = IosUtils(format_udid_info, user_obj, app_obj) ios_sign_obj = IosUtils(format_udid_info, user_obj, app_obj)
status, msg = ios_sign_obj.sign_ipa(client_ip) status, result = ios_sign_obj.sign_ipa(client_ip)
if ios_sign_obj.developer_obj: if ios_sign_obj.developer_obj:
if not status: if status:
add_sign_message(user_obj, ios_sign_obj.developer_obj, app_obj, '签名失败了', msg, False) add_sign_message(user_obj, ios_sign_obj.developer_obj, app_obj, '签名成功', result, True)
else:
add_sign_message(user_obj, ios_sign_obj.developer_obj, app_obj, '签名成功', msg, True)
except Exception as e: except Exception as e:
logger.error(f"run_sign_task failed. udid_info:{format_udid_info} app_obj:{app_obj} Exception:{e}") logger.error(f"run_sign_task failed. udid_info:{format_udid_info} app_obj:{app_obj} Exception:{e}")
return '系统内部错误,请稍后再试或联系管理员' msg = '系统内部错误,请稍后再试或联系管理员'
code = 5000
return {'code': code, 'msg': msg}
if not status: if not status:
code = msg.get("code", -1) code = result.get("code", -1)
if code == 0: if code == 1000:
msg = "" msg = ""
elif code == 1005: elif code == 1005:
msg = "签名余额不足" msg = "签名余额不足"
elif code == 1002:
msg = "维护中"
elif code == 1003: elif code == 1003:
msg = "应用余额不足" msg = "应用余额不足"
elif code == 1007: elif code == 1007:
msg = "设备注册中,请耐心等待" msg = "设备注册中,请耐心等待"
elif code in [1004, 1001, 1009]: elif code in [1004, 1001, 1009]:
msg = msg.get('msg', '未知错误') msg = result.get('msg', '未知错误')
else: else:
code = 5000
msg = '系统内部错误,请稍后再试或联系管理员' msg = '系统内部错误,请稍后再试或联系管理员'
message = f"return_info:[code:{code},msg:{msg}] raw_info:[{result}]"
if ios_sign_obj.developer_obj:
add_sign_message(user_obj, ios_sign_obj.developer_obj, app_obj, '签名失败了', message, False)
else:
logger.error(f"{user_obj} {app_obj} 签名失败了:{message}")
else: else:
msg = "" msg = ""
return msg code = 1000
result = {'code': code, 'msg': msg}
if app_obj.supersign_redirect_url and (code == 1005 or (code == 1007 and app_obj.abnormal_redirect)):
result['redirect'] = app_obj.supersign_redirect_url
return result
def run_resign_task(app_id, need_download_profile=True, force=True, developers_filter=None): def run_resign_task(app_id, need_download_profile=True, force=True, developers_filter=None):

@ -155,6 +155,10 @@ class DeviceUDIDSerializer(serializers.ModelSerializer):
udid = serializers.CharField(source="udid.udid") udid = serializers.CharField(source="udid.udid")
is_mine = serializers.SerializerMethodField() is_mine = serializers.SerializerMethodField()
other_uid = serializers.SerializerMethodField() other_uid = serializers.SerializerMethodField()
can_resign = serializers.SerializerMethodField()
def get_can_resign(self, obj):
return obj.udid.developerid.status in Config.DEVELOPER_RESIGN_STATUS
def get_issuer_id(self, obj): def get_issuer_id(self, obj):
issuer_id = obj.udid.developerid.issuer_id issuer_id = obj.udid.developerid.issuer_id

@ -109,6 +109,8 @@ def resign_by_app_id_and_developer(app_id, developer_id, developer_app_id, need_
return False, '清理执行中,请等待' return False, '清理执行中,请等待'
d_time = time.time() d_time = time.time()
if need_download_profile: if need_download_profile:
if developer_obj.status not in Config.DEVELOPER_RESIGN_STATUS:
return False, f'开发者状态 {developer_obj.get_status_display()},无法下载描述文件'
with cache.lock(f"make_and_download_profile_{developer_obj.issuer_id}_{app_obj.app_id}", timeout=60): with cache.lock(f"make_and_download_profile_{developer_obj.issuer_id}_{app_obj.app_id}", timeout=60):
IosUtils.modify_capability(developer_obj, app_obj, developer_app_id) IosUtils.modify_capability(developer_obj, app_obj, developer_app_id)
status, download_profile_result = IosUtils.make_and_download_profile(app_obj, status, download_profile_result = IosUtils.make_and_download_profile(app_obj,
@ -402,26 +404,31 @@ def get_developer_user_by_app_udid(user_objs, udid, app_obj, private_first=True,
return obj, status return obj, status
else: else:
logger.warning( logger.warning(
f"udid:{udid} app_obj:{app_obj} find normal developer failed. now find abnormal device developer") f"udid:{udid} app_obj:{app_obj} find udid from normal developer failed. now find abnormal device developer")
obj, status = get_developer_user_by_app_exist_udid(user_objs, udid, app_obj, [AppleDeveloperStatus.DEVICE_ABNORMAL]) obj, status = get_developer_user_by_app_exist_udid(user_objs, udid, app_obj, [AppleDeveloperStatus.DEVICE_ABNORMAL])
if status: if status:
return obj, status return obj, status
else: else:
logger.warning(f"udid:{udid} app_obj:{app_obj} find abnormal developer failed. now find can wait developer") logger.warning(
f"udid:{udid} app_obj:{app_obj} find udid from abnormal developer failed. now find can wait developer")
if UserConfig(app_obj.user_id).DEVELOPER_WAIT_ABNORMAL_STATE: if UserConfig(app_obj.user_id).DEVELOPER_WAIT_ABNORMAL_STATE:
obj, status = get_developer_user_by_app_exist_udid(user_objs, udid, app_obj, Config.DEVELOPER_WAIT_STATUS) obj, status = get_developer_user_by_app_exist_udid(user_objs, udid, app_obj, Config.DEVELOPER_WAIT_STATUS)
if status: if status:
return obj, status return obj, status
else: else:
logger.warning(f"udid:{udid} app_obj:{app_obj} find abnormal developer failed. now find register developer") logger.warning(
f"udid:{udid} app_obj:{app_obj} find udid from abnormal developer failed. now find register developer")
# 新设备查找策略 # 新设备查找策略
# 查询开发者正常的状态 # 查询开发者正常的状态
obj, status = get_developer_user_by_app_new_udid(user_objs, udid, app_obj, status_choice, private_first) obj, status = get_developer_user_by_app_new_udid(user_objs, udid, app_obj, status_choice, private_first)
if obj: if obj:
return obj, status return obj, status
else:
logger.warning(
f"udid:{udid} app_obj:{app_obj} register udid from normal developer failed. now find abnormal device developer")
# 个人配置允许查询异常设备 # 个人配置允许查询异常设备
if UserConfig(app_obj.user_id).DEVELOPER_WAIT_ABNORMAL_DEVICE and UserConfig( if UserConfig(app_obj.user_id).DEVELOPER_WAIT_ABNORMAL_DEVICE and UserConfig(
@ -446,7 +453,7 @@ def get_developer_obj_by_others(user_obj, udid, app_obj, read_only):
def check_sign_is_exists(user_obj, app_obj, udid, developer_obj, sign=True): def check_sign_is_exists(user_obj, app_obj, udid, developer_obj, sign=True):
d_result = {'code': 0, 'msg': 'success'} d_result = {'code': 1000, 'msg': 'success'}
app_udid_obj = AppUDID.objects.filter(app_id=app_obj, udid__udid=udid, udid__developerid=developer_obj).first() app_udid_obj = AppUDID.objects.filter(app_id=app_obj, udid__udid=udid, udid__developerid=developer_obj).first()
if app_udid_obj and app_udid_obj.sign_status >= SignStatus.PROFILE_DOWNLOAD_COMPLETE: if app_udid_obj and app_udid_obj.sign_status >= SignStatus.PROFILE_DOWNLOAD_COMPLETE:
if app_udid_obj.sign_status == SignStatus.SIGNATURE_PACKAGE_COMPLETE: if app_udid_obj.sign_status == SignStatus.SIGNATURE_PACKAGE_COMPLETE:
@ -605,7 +612,7 @@ class IosUtils(object):
return True return True
def check_sign_permission(self): def check_sign_permission(self):
d_result = {'code': 0, 'msg': 'success'} d_result = {'code': 1000, 'msg': 'success'}
state, used_num = check_app_sign_limit(self.app_obj) state, used_num = check_app_sign_limit(self.app_obj)
if not state: if not state:
d_result['code'] = 1003 d_result['code'] = 1003
@ -869,7 +876,6 @@ class IosUtils(object):
return True, True return True, True
def sign_failed_fun(self, d_result, msg): def sign_failed_fun(self, d_result, msg):
d_result['code'] = 1002
d_result['msg'] = msg d_result['msg'] = msg
logger.error(d_result) logger.error(d_result)
add_sign_message(self.user_obj, self.developer_obj, self.app_obj, '签名失败', msg, False) add_sign_message(self.user_obj, self.developer_obj, self.app_obj, '签名失败', msg, False)
@ -885,7 +891,7 @@ class IosUtils(object):
status, msg = self.check_sign_permission() status, msg = self.check_sign_permission()
if not status: if not status:
return status, msg return status, msg
d_result = {'code': 0, 'msg': 'success'} d_result = {'code': 1000, 'msg': 'success'}
result = check_sign_is_exists(self.user_obj, self.app_obj, self.udid, self.developer_obj) result = check_sign_is_exists(self.user_obj, self.app_obj, self.udid, self.developer_obj)
if result: if result:
@ -939,20 +945,20 @@ class IosUtils(object):
add_new_bundles_prefix) add_new_bundles_prefix)
if not status: if not status:
if 'UNEXPECTED_ERROR' in str(did_udid_result): if 'UNEXPECTED_ERROR' in str(did_udid_result):
return False, {} return False, {'code': 1002, 'msg': did_udid_result}
if 'DEVELOPER_WAIT_ABNORMAL_DEVICE' in str(did_udid_result): if 'DEVELOPER_WAIT_ABNORMAL_DEVICE' in str(did_udid_result):
return False, {'code': 1007, 'msg': '设备注册中,请耐心等待'} return False, {'code': 1007, 'msg': '设备注册中,请耐心等待'}
msg = f"app_id {self.app_obj} register devices failed. {did_udid_result}" msg = f"app_id {self.app_obj} register devices failed. {did_udid_result}"
self.sign_failed_fun(d_result, msg) self.sign_failed_fun(d_result, msg)
continue continue
if status and 'continue' in [str(did_udid_result)]: if status and 'continue' in [str(did_udid_result)]:
return True, True return True, 'device udid is not exists. so return and exit'
with cache.lock(add_new_bundles_prefix, timeout=360): with cache.lock(add_new_bundles_prefix, timeout=360):
status, bundle_result = IosUtils.check_or_add_new_bundles(self.app_obj, self.developer_obj, status, bundle_result = IosUtils.check_or_add_new_bundles(self.app_obj, self.developer_obj,
add_new_bundles_prefix) add_new_bundles_prefix)
if not status: if not status:
if 'UNEXPECTED_ERROR' in str(bundle_result): if 'UNEXPECTED_ERROR' in str(bundle_result):
return False, {} return False, {'code': 1002, 'msg': bundle_result}
msg = f"app_id {self.app_obj} create bundles failed. {bundle_result}" msg = f"app_id {self.app_obj} create bundles failed. {bundle_result}"
self.sign_failed_fun(d_result, msg) self.sign_failed_fun(d_result, msg)
continue continue
@ -970,7 +976,7 @@ class IosUtils(object):
new_did_list.append(did_udid[0]) new_did_list.append(did_udid[0])
new_udid_list.append(did_udid[1]) new_udid_list.append(did_udid[1])
if not new_did_list: if not new_did_list:
return True, True return True, f'udid {self.udid} not in new_did_list. {self.app_obj}'
logger.warning( logger.warning(
f'app {self.app_obj} receive {len(new_did_list)} did_udid_result: {new_did_list}') f'app {self.app_obj} receive {len(new_did_list)} did_udid_result: {new_did_list}')
status, download_profile_result = IosUtils.make_and_download_profile(self.app_obj, status, download_profile_result = IosUtils.make_and_download_profile(self.app_obj,
@ -979,13 +985,14 @@ class IosUtils(object):
new_did_list=new_did_list) new_did_list=new_did_list)
if not status: if not status:
if 'UNEXPECTED_ERROR' in str(download_profile_result): if 'UNEXPECTED_ERROR' in str(download_profile_result):
return False, {} return False, {'code': 1002, 'msg': download_profile_result}
msg = f"app_id {self.app_obj} download profile failed. {download_profile_result}" msg = f"app_id {self.app_obj} download profile failed. {download_profile_result}"
self.sign_failed_fun(d_result, msg) self.sign_failed_fun(d_result, msg)
continue continue
else: else:
if 'continue' in [str(did_udid_result), str(download_profile_result)]: if 'continue' in [str(did_udid_result), str(download_profile_result)]:
return True, True # 该情况估计是执行了回滚清理应用操作,导致异常,大概率是开发证书丢失或苹果开发平台数据被误删
return True, f'{self.app_obj} developer {self.developer_obj} may be rollback'
locker = { locker = {
'locker_key': f"run_sign_{self.app_obj.app_id}_{self.developer_obj.issuer_id}", 'locker_key': f"run_sign_{self.app_obj.app_id}_{self.developer_obj.issuer_id}",
"timeout": 60 * 5 "timeout": 60 * 5
@ -1014,11 +1021,11 @@ class IosUtils(object):
if not check_sign_is_exists(user_obj, app_obj, did_udid, developer_obj, False): if not check_sign_is_exists(user_obj, app_obj, did_udid, developer_obj, False):
new_did_list.append(did_udid) new_did_list.append(did_udid)
if not new_did_list: if not new_did_list:
return True, True return True, f"{app_obj} not udid .so return, maybe it was deleted"
else: else:
udid_list = new_did_list udid_list = new_did_list
udid_list = list(set(udid_list)) udid_list = list(set(udid_list))
d_result = {'code': 0, 'msg': 'success'} d_result = {'code': 1000, 'msg': 'success'}
AppUDID.objects.filter(app_id=app_obj, udid__udid__in=udid_list, AppUDID.objects.filter(app_id=app_obj, udid__udid__in=udid_list,
udid__developerid=developer_obj, udid__developerid=developer_obj,
sign_status=SignStatus.APP_REGISTRATION_COMPLETE).update( sign_status=SignStatus.APP_REGISTRATION_COMPLETE).update(

@ -60,9 +60,10 @@ class AppSignInfoView(APIView):
logger.info(f"app_id:{app_id} update old data:{app_obj.__dict__}") logger.info(f"app_id:{app_id} update old data:{app_obj.__dict__}")
update_fields = [] update_fields = []
if app_obj.issupersign: if app_obj.issupersign:
app_obj.supersign_limit_number = data.get("supersign_limit_number", app_obj.supersign_limit_number = data.get("supersign_limit_number", app_obj.supersign_limit_number)
app_obj.supersign_limit_number) app_obj.supersign_redirect_url = data.get("supersign_redirect_url", app_obj.supersign_redirect_url)
update_fields.append("supersign_limit_number") app_obj.abnormal_redirect = data.get("abnormal_redirect", app_obj.abnormal_redirect)
update_fields.extend(["supersign_limit_number", "supersign_redirect_url", "abnormal_redirect"])
if app_obj.supersign_type in [x[0] for x in list(app_obj.supersign_type_choices)]: if app_obj.supersign_type in [x[0] for x in list(app_obj.supersign_type_choices)]:
if app_obj.supersign_type != data.get("supersign_type", app_obj.supersign_type): if app_obj.supersign_type != data.get("supersign_type", app_obj.supersign_type):
do_sign_flag = 1 do_sign_flag = 1

@ -141,7 +141,7 @@ class TaskView(APIView):
if status and result.get('data'): if status and result.get('data'):
result = result.get('data') result = result.get('data')
if result.successful(): if result.successful():
res.msg = result.get(propagate=False) res.data = result.get(propagate=False)
return Response(res.dict) return Response(res.dict)
elif result.state in ['PENDING']: elif result.state in ['PENDING']:
res.msg = '签名队列中' res.msg = '签名队列中'
@ -185,7 +185,7 @@ class TaskView(APIView):
res.msg = '下载授权码失效或有误' res.msg = '下载授权码失效或有误'
if check_user_udid_black(app_obj.user_id, udid): if check_user_udid_black(app_obj.user_id, udid):
res.code = 1007 res.code = 1005
res.msg = '设备注册中,请耐心等待' res.msg = '设备注册中,请耐心等待'
if res.code != 1000: if res.code != 1000:
@ -197,12 +197,13 @@ class TaskView(APIView):
logger.info(f"sign app {app_obj} task_id:{task_id}") logger.info(f"sign app {app_obj} task_id:{task_id}")
try: try:
result = c_task.get(propagate=False, timeout=1) result = c_task.get(propagate=False, timeout=1)
logger.info(f"sign app {app_obj} task_id:{task_id} result:{result}")
except TimeoutError: except TimeoutError:
logger.error(f"get task task_id:{task_id} result timeout") logger.error(f"app {app_obj} get task task_id:{task_id} result timeout. udid {format_udid_info}")
result = '' result = {'task_id': task_id}
if c_task.successful(): if c_task.successful():
c_task.forget() c_task.forget()
res.result = result res.data = result
else: else:
res.task_id = task_id res.task_id = task_id
return Response(res.dict) return Response(res.dict)

Loading…
Cancel
Save