优化代码,增加设备删除控制,增加设备被封状态

dependabot/npm_and_yarn/fir_admin/url-parse-1.5.10
MMXX 3 years ago
parent ef335e118a
commit a8c1df58ee
  1. 167
      fir_client/src/components/user/FirSuperSignBase.vue
  2. 24
      fir_ser/api/migrations/0029_auto_20220102_1522.py
  3. 4
      fir_ser/api/models.py
  4. 27
      fir_ser/api/utils/app/iossignapi.py
  5. 24
      fir_ser/api/utils/app/supersignutils.py
  6. 6
      fir_ser/api/utils/serializer.py
  7. 52
      fir_ser/api/views/supersign.py

@ -79,6 +79,16 @@
<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="清理禁用设备" label-width="110px" style="text-align: left">
<el-switch
v-model="editdeveloperinfo.clean_status"
:active-value="true"
:inactive-value="false"
active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
<el-tag style="margin-left: 10px" type="warning"> 清理数据的时候是否同时将开发者设备禁用默认不禁用</el-tag>
</el-form-item>
<el-form-item label="证书id" label-width="110px">
<el-input v-model="editdeveloperinfo.certid" :disabled='isedit'/>
</el-form-item>
@ -202,6 +212,44 @@
<el-button @click="closeDeviceBillInfo">关闭</el-button>
</span>
</el-dialog>
<el-dialog :close-on-click-modal="false" :destroy-on-close="true" :visible.sync="udeviceappinfoVisible"
center title="设备消耗应用详细信息" width="750px">
<el-table
v-loading="loading"
:data="app_used_info_list"
border
stripe
style="width: 100%">
<el-table-column
align="center"
label="应用名称"
prop="bundle_name"
>
</el-table-column>
<el-table-column
align="center"
label="应用ID"
prop="bundle_id"
>
</el-table-column>
<el-table-column
:formatter="deviceformatter"
align="center"
label="日期"
prop="created_time"
width="160">
</el-table-column>
</el-table>
<span slot="footer">
<el-button @click="udeviceappinfoVisible=false">关闭</el-button>
</span>
</el-dialog>
<el-dialog :close-on-click-modal="false" :destroy-on-close="true" :visible.sync="setdeveloperstatusVisible"
style="text-align:center" title="批量修改账户状态" width="700px">
@ -586,6 +634,17 @@
align="center"
label="设备UDID"
prop="udid">
<template slot-scope="scope">
<el-popover placement="top" trigger="hover">
<p>该设备UDID 被分配到了 {{ scope.row.app_used_count }} 个应用</p>
<el-button v-if="scope.row.app_used_count > 0" size="mini" @click="show_app_used_info(scope.row)">
点击查看分配信息
</el-button>
<div slot="reference" class="name-wrapper">
<span>{{ scope.row.udid }}</span>
</div>
</el-popover>
</template>
</el-table-column>
<el-table-column
align="center"
@ -604,10 +663,16 @@
label="设备状态"
width="110">
<template slot-scope="scope">
<el-tag v-if="!scope.row.status" type="info">禁用</el-tag>
<el-tag v-else>
启用
</el-tag>
<el-tooltip v-if="!scope.row.status" content="点击启用">
<el-link :underline="false" type="info" @click="changeDevice(scope.row,1)">
<el-tag type="info">禁用</el-tag>
</el-link>
</el-tooltip>
<el-tooltip v-else content="点击禁用,禁用会自动清理已经安装的数据">
<el-link :underline="false" @click="changeDevice(scope.row,0)">
<el-tag>启用</el-tag>
</el-link>
</el-tooltip>
</template>
</el-table-column>
<el-table-column
@ -706,12 +771,12 @@
</el-popover>
</template>
</el-table-column>
<el-table-column
v-if="$store.state.userinfo&&$store.state.userinfo.role === 3"
align="center"
label="被使用户uid"
prop="other_uid">
</el-table-column>
<!-- <el-table-column-->
<!-- v-if="$store.state.userinfo&&$store.state.userinfo.role === 3"-->
<!-- align="center"-->
<!-- label="被使用户uid"-->
<!-- prop="other_uid">-->
<!-- </el-table-column>-->
<el-table-column
:formatter="deviceformatter"
align="center"
@ -814,12 +879,12 @@
</el-popover>
</template>
</el-table-column>
<el-table-column
v-if="$store.state.userinfo&&$store.state.userinfo.role === 3"
align="center"
label="被使用户uid"
prop="other_uid">
</el-table-column>
<!-- <el-table-column-->
<!-- v-if="$store.state.userinfo&&$store.state.userinfo.role === 3"-->
<!-- align="center"-->
<!-- label="被使用户uid"-->
<!-- prop="other_uid">-->
<!-- </el-table-column>-->
<el-table-column
:formatter="deviceformatter"
align="center"
@ -831,17 +896,26 @@
align="center"
fixed="right"
label="操作"
width="100">
width="150">
<template slot-scope="scope">
<el-button
v-if="scope.row.is_mine"
size="mini"
type="danger"
@click="udidDeleteFun(scope)">删除
</el-button>
<el-tag v-else>
</el-tag>
<div>
<el-tooltip content="仅仅删除数据库数据,不操作苹果开发者设备" placement="top">
<el-button
size="mini"
type="danger"
@click="udidDeleteFun(scope,0)">仅删除
</el-button>
</el-tooltip>
</div>
<div style="margin-top: 5px">
<el-tooltip content="删除的同时,会检测并同时禁用苹果开发者设备" placement="bottom">
<el-button
size="mini"
type="danger"
@click="udidDeleteFun(scope,1)">删除并禁用设备
</el-button>
</el-tooltip>
</div>
</template>
</el-table-column>
</el-table>
@ -1111,7 +1185,9 @@ export default {
developer_status_choice: [],
multipleSelection: [],
setdeveloperstatusVisible: false,
change_developer_status: ''
change_developer_status: '',
udeviceappinfoVisible: false,
app_used_info_list: []
}
}, watch: {
'dialogaddDeveloperVisible': function () {
@ -1121,6 +1197,24 @@ export default {
}
},
methods: {
changeDevice(info, disabled) {
this.iosudevicesFun("PUT", {developer_id: info.developer_id, udid: info.udid, disabled: disabled})
},
show_app_used_info(info) {
this.loading = true;
iosdevices(data => {
if (data.code === 1000) {
this.app_used_info_list = data.data;
this.udeviceappinfoVisible = true
} else {
this.$message.error("数据获取失败" + data.msg)
this.app_used_info_list = [];
}
this.loading = false;
}, {
"methods": 'GET', "data": {udid: info.udid, issuer_id: info.developer_id, page: 1, size: 200}
})
},
setdeveloperstatusFun() {
if (this.multipleSelection && this.multipleSelection.length > 0) {
this.setdeveloperstatusVisible = true
@ -1273,13 +1367,13 @@ export default {
return '#F50346';
}
},
udidDeleteFun(scope) {
udidDeleteFun(scope, disabled) {
this.$confirm('此操作会禁用该苹果开发者账户下面的该设备,可能会导致超级签包的闪退, 是否继续?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.iosdevicesudidFun('DELETE', {id: scope.row.id, aid: scope.row.app_id}, scope);
this.iosdevicesudidFun('DELETE', {id: scope.row.id, aid: scope.row.app_id, disabled: disabled}, scope);
}).catch(() => {
this.$message({
type: 'info',
@ -1464,7 +1558,7 @@ export default {
data.appnamesearch = this.appnamesearch.replace(/^\s+|\s+$/g, "");
this.iosdevicerankFun({"methods": "GET", "data": data})
} else if (tabname === "iosudevices") {
this.iosudevicesFun("GET", data, null)
this.iosudevicesFun("GET", data)
}
},
@ -1559,7 +1653,7 @@ export default {
} else {
this.$message.error("操作失败")
}
if (params.methods === 'PUT') {
if (params.methods === 'PUT' || params.methods === 'DELETE') {
this.get_data_from_tabname(this.activeName, {
"size": this.pagination.pagesize,
"page": this.pagination.currentPage
@ -1651,7 +1745,7 @@ export default {
"methods": action, "data": data
})
},
iosudevicesFun(action, data, scope) {
iosudevicesFun(action, data) {
if (action !== 'GET') {
this.loadingfun = this.$loading({
lock: true,
@ -1664,13 +1758,14 @@ export default {
}
iosudevices(data => {
if (data.code === 1000) {
if (action !== "DELETE") {
if (action !== "PUT") {
this.developer_udevices_lists = data.data;
this.pagination.total = data.count;
} else {
if (scope) {
this.app_udid_lists = removeAaary(this.app_udid_lists, scope.row)
}
this.get_data_from_tabname(this.activeName, {
"size": this.pagination.pagesize,
"page": this.pagination.currentPage
})
}
} else {
this.$message.error("操作失败了 " + data.msg);

@ -0,0 +1,24 @@
# Generated by Django 3.2.3 on 2022-01-02 15:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0028_auto_20211228_1454'),
]
operations = [
migrations.AddField(
model_name='appiosdeveloperinfo',
name='clean_status',
field=models.BooleanField(default=False, verbose_name='清理是否同时禁用设备ID'),
),
migrations.AlterField(
model_name='appiosdeveloperinfo',
name='status',
field=models.SmallIntegerField(
choices=[(-1, '疑似被封'), (0, '未激活'), (1, '已激活'), (2, '协议待同意'), (3, '维护中'), (4, '证书过期'), (5, '状态异常')],
default=0, verbose_name='账户状态'),
),
]

@ -282,9 +282,11 @@ class AppIOSDeveloperInfo(models.Model):
auth_type = models.SmallIntegerField(choices=auth_type_choices, default=0, verbose_name="认证类型")
# 协议待同意和维护中:代表只读,不可创建和注册新设备号
status_choices = ((0, '未激活'), (1, '已激活'), (2, '协议待同意'), (3, '维护中'), (4, '证书过期'), (5, '状态异常'))
status_choices = ((-1, '疑似被封'), (0, '未激活'), (1, '已激活'), (2, '协议待同意'), (3, '维护中'), (4, '证书过期'), (5, '状态异常'))
status = models.SmallIntegerField(choices=status_choices, verbose_name="账户状态", default=0)
clean_status = models.BooleanField(verbose_name="清理是否同时禁用设备ID", default=False)
class Meta:
verbose_name = '苹果开发者账户'
verbose_name_plural = "苹果开发者账户"

@ -8,6 +8,7 @@ import datetime
import logging
import os
import re
import time
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)
@ -212,6 +213,10 @@ def check_error_call_back(error, developer_pk):
msg = '请登录 https://developer.apple.com/account/ 并同意最新协议'
status = 2
if status is not None:
developer_obj = AppIOSDeveloperInfo.objects.filter(pk=developer_pk).first()
if developer_obj:
if developer_obj.status == -1 and status == 5:
status = -1
AppIOSDeveloperInfo.objects.filter(pk=developer_pk).update(status=status)
logger.error(f"{msg} {error}")
return msg if msg else error
@ -225,6 +230,28 @@ class AppDeveloperApiV2(object):
self.cert_id = cert_id
self.developer_pk = developer_pk
def __getattribute__(self, name):
attr = object.__getattribute__(self, name)
if hasattr(attr, '__call__'):
def func(*args, **kwargs):
if attr.__name__ in ['active', 'get_device']:
return attr(*args, **kwargs)
else:
if AppIOSDeveloperInfo.objects.filter(pk=self.developer_pk, status__in=[1, 3, 4]).first():
start_time = time.time()
logger.info(f'{self.issuer_id} calling {attr.__name__} time:{start_time}')
result = attr(*args, **kwargs)
logger.info(f'{self.issuer_id} done {attr.__name__} used time:{time.time() - start_time}')
return result
else:
result = False, {'return_info': '开发者状态异常'}
logger.warning(f'{self.issuer_id} can not calling {attr.__name__} {result}')
return result
return func
else:
return attr
def active(self):
result = {'data': []}
try:

@ -845,7 +845,7 @@ class IosUtils(object):
return True, d_result
@staticmethod
def disable_udid(udid_obj, app_id):
def disable_udid(udid_obj, app_id, disabled=False):
usedeviceobj = APPSuperSignUsedInfo.objects.filter(udid=udid_obj, app_id_id=app_id)
if usedeviceobj:
@ -853,7 +853,7 @@ class IosUtils(object):
# 需要判断该设备在同一个账户下 的多个应用,若存在,则不操作
udid_lists = list(
APPSuperSignUsedInfo.objects.values_list("udid__udid__udid").filter(developerid=developer_obj))
IosUtils.do_disable_device(developer_obj, udid_lists, udid_obj)
IosUtils.do_disable_device(developer_obj, udid_lists, udid_obj, disabled)
DeveloperDevicesID.objects.filter(udid__appudid=udid_obj, developerid=developer_obj,
app_id_id=app_id).delete()
udid_obj.delete()
@ -865,13 +865,27 @@ class IosUtils(object):
delete_app_profile_file(developer_obj, app_obj)
@staticmethod
def do_disable_device(developer_obj, udid_lists, udid_obj):
if udid_lists.count((udid_obj.udid.udid,)) == 1:
def do_disable_device(developer_obj, udid_lists, udid_obj, disabled):
if udid_lists.count((udid_obj.udid.udid,)) == 1 and disabled:
app_api_obj = get_api_obj(developer_obj)
app_api_obj.set_device_status("disable", udid_obj.udid.serial, udid_obj.udid.product, udid_obj.udid.udid,
udid_obj.udid.udid)
UDIDsyncDeveloper.objects.filter(udid=udid_obj.udid.udid, developerid=developer_obj).update(status=False)
@staticmethod
def do_enable_device_by_sync(developer_obj, udid_sync_obj):
app_api_obj = get_api_obj(developer_obj)
app_api_obj.set_device_status("enable", udid_sync_obj.serial, udid_sync_obj.product, udid_sync_obj.udid,
udid_sync_obj.udid)
UDIDsyncDeveloper.objects.filter(pk=udid_sync_obj.pk, developerid=developer_obj).update(status=True)
@staticmethod
def do_disable_device_by_sync(developer_obj, udid_sync_obj):
app_api_obj = get_api_obj(developer_obj)
app_api_obj.set_device_status("disable", udid_sync_obj.serial, udid_sync_obj.product, udid_sync_obj.udid,
udid_sync_obj.udid)
UDIDsyncDeveloper.objects.filter(pk=udid_sync_obj.pk, developerid=developer_obj).update(status=False)
@staticmethod
def clean_udid_by_app_obj(app_obj, developer_obj):
@ -882,7 +896,7 @@ class IosUtils(object):
for SuperSignUsed_obj in APPSuperSignUsedInfo.objects.filter(app_id=app_obj, developerid=developer_obj):
try:
udid_obj = SuperSignUsed_obj.udid
IosUtils.do_disable_device(developer_obj, udid_lists, udid_obj)
IosUtils.do_disable_device(developer_obj, udid_lists, udid_obj, developer_obj.clean_status)
SuperSignUsed_obj.delete()
DeveloperDevicesID.objects.filter(udid__appudid=udid_obj, developerid=developer_obj,
app_id=app_obj).delete()

@ -640,6 +640,12 @@ class DeveloperDeviceSerializer(serializers.ModelSerializer):
developer_description = serializers.CharField(source="developerid.description")
developer_status = serializers.CharField(source="developerid.get_status_display")
app_used_count = serializers.SerializerMethodField()
def get_app_used_count(self, obj):
return models.DeveloperDevicesID.objects.filter(udid=obj, developerid=obj.developerid).values(
'app_id').distinct().count()
class DeviceUDIDSerializer(serializers.ModelSerializer):
class Meta:

@ -14,7 +14,7 @@ from rest_framework.response import Response
from rest_framework.views import APIView
from api.models import AppIOSDeveloperInfo, APPSuperSignUsedInfo, AppUDID, IosDeveloperPublicPoolBill, \
UDIDsyncDeveloper, AppleDeveloperToAppUse, Apps, DeveloperAppID, APPToDeveloper
UDIDsyncDeveloper, AppleDeveloperToAppUse, Apps, DeveloperAppID, APPToDeveloper, DeveloperDevicesID
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
@ -198,6 +198,10 @@ class DeveloperView(APIView):
developer_obj.description = data.get("description", developer_obj.description)
update_fields.append("description")
developer_obj.clean_status = data.get("clean_status", developer_obj.clean_status)
update_fields.append("clean_status")
private_key_id = data.get("private_key_id", developer_obj.private_key_id)
p8key = data.get("p8key", developer_obj.p8key)
if private_key_id != "" and private_key_id != developer_obj.private_key_id:
@ -215,7 +219,7 @@ class DeveloperView(APIView):
update_fields.append("status")
try:
update_fields.append("status")
# update_fields.append("status")
developer_obj.save(update_fields=update_fields)
logger.info(
f"user {request.user} ios developer {developer_obj} update now data {developer_obj.__dict__}")
@ -340,12 +344,17 @@ class AppUDIDUsedView(APIView):
res = BaseResponse()
pk = request.query_params.get("id", None)
app_id = request.query_params.get("aid", None)
app_udid_obj = AppUDID.objects.filter(pk=pk)
disabled = request.query_params.get("disabled", None)
if disabled is not None and disabled == '1':
disabled = True
else:
disabled = False
app_udid_obj = AppUDID.objects.filter(pk=pk, app_id__user_id=request.user)
if app_udid_obj:
super_sign_used_obj = APPSuperSignUsedInfo.objects.filter(udid=app_udid_obj.first()).first()
if super_sign_used_obj and super_sign_used_obj.developerid.user_id.pk == request.user.pk:
logger.error(f"user {request.user} delete devices {app_udid_obj}")
IosUtils.disable_udid(app_udid_obj.first(), app_id)
IosUtils.disable_udid(app_udid_obj.first(), app_id, disabled)
app_udid_obj.delete()
else:
res.code = 10002
@ -376,20 +385,31 @@ class DeveloperDeviceView(APIView):
res.count = super_sign_used_objs.count()
return Response(res.dict)
def delete(self, request):
def put(self, request):
res = BaseResponse()
pk = request.query_params.get("id", None)
app_id = request.query_params.get("aid", None)
app_udid_obj = AppUDID.objects.filter(pk=pk, app_id__user_id=request.user)
if app_udid_obj:
super_sign_used_obj = APPSuperSignUsedInfo.objects.filter(udid=app_udid_obj.first()).first()
if super_sign_used_obj and super_sign_used_obj.developerid.user_id.pk == request.user.pk:
logger.error(f"user {request.user} delete devices {app_udid_obj}")
IosUtils.disable_udid(app_udid_obj.first(), app_id)
app_udid_obj.delete()
developer_id = request.data.get("developer_id", None)
udid = request.data.get("udid", None)
disabled = request.data.get("disabled", None)
if developer_id and udid and disabled is not None and disabled in [0, 1]:
developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=request.user, issuer_id=developer_id).first()
udid_sync_obj_queryset = UDIDsyncDeveloper.objects.filter(udid=udid, developerid=developer_obj).all()
if disabled == 1:
for udid_sync_obj in udid_sync_obj_queryset:
IosUtils.do_enable_device_by_sync(developer_obj, udid_sync_obj)
else:
res.code = 10002
res.msg = '公共账号池不允许删除'
app_udid_obj_list = AppUDID.objects.filter(udid__udid=udid, app_id__user_id=request.user,
udid__developerid=developer_obj).all()
for app_udid_obj in app_udid_obj_list:
for app_id_info in DeveloperDevicesID.objects.filter(udid=app_udid_obj.udid,
developerid=developer_obj).values(
'app_id').all().distinct():
logger.error(f"user {request.user} delete devices {app_udid_obj}")
IosUtils.disable_udid(app_udid_obj, app_id_info.get('app_id'), True)
AppUDID.objects.filter(pk=app_udid_obj.pk).delete()
for udid_sync_obj in udid_sync_obj_queryset:
IosUtils.do_disable_device_by_sync(developer_obj, udid_sync_obj)
return Response(res.dict)

Loading…
Cancel
Save