增加设备消化账单

publicsignpoll
youngS 3 years ago
parent 7d781de388
commit 50da6044a4
  1. 2
      fir_client/src/components/FirDownload.vue
  2. 2
      fir_client/src/components/ShortDownload.vue
  3. 128
      fir_client/src/components/user/FirSuperSignBase.vue
  4. 15
      fir_client/src/restful/index.js
  5. 1
      fir_ser/api/migrations/0015_iosdeveloperpublicpoolbill_remoteclientinfo.py
  6. 26
      fir_ser/api/migrations/0018_devicequeue.py
  7. 17
      fir_ser/api/migrations/0019_iosdeveloperpublicpoolbill_udid.py
  8. 9
      fir_ser/api/models.py
  9. 2
      fir_ser/api/tasks.py
  10. 3
      fir_ser/api/urls.py
  11. 66
      fir_ser/api/utils/app/supersignutils.py
  12. 44
      fir_ser/api/utils/serializer.py
  13. 15
      fir_ser/api/utils/utils.py
  14. 2
      fir_ser/api/views/apps.py
  15. 25
      fir_ser/api/views/supersign.py

@ -612,7 +612,7 @@
}
} else if (data.code === 1002) {
window.location.href = location.href.replace(location.search, '');
}else if (data.code === 302 && data.data) {
} else if (data.code === 302 && data.data) {
window.location.href = data.data;
} else {
if (data.msg) {

@ -597,7 +597,7 @@
}
} else if (data.code === 1002) {
window.location.href = location.href.replace(location.search, '');
}else if (data.code === 302 && data.data) {
} else if (data.code === 302 && data.data) {
window.location.href = data.data;
} else {
this.iserror = true;

@ -126,6 +126,7 @@
<el-table-column
fixed
prop="issuer_id"
align="center"
label="用户 issuer_id"
width="300">
<template slot-scope="scope">
@ -147,6 +148,7 @@
</el-table-column>
<el-table-column
prop="is_actived"
align="center"
label="是否激活"
width="110">
<template slot-scope="scope">
@ -160,6 +162,7 @@
<el-table-column
prop="certid"
label="账户状态"
align="center"
width="100">
<template slot-scope="scope">
<el-popover trigger="hover" placement="top">
@ -178,6 +181,7 @@
<el-table-column
prop="usable_number"
label="可用设备"
align="center"
width="60">
<template slot-scope="scope">
<el-popover trigger="hover" placement="top">
@ -194,6 +198,7 @@
<el-table-column
prop="use_number"
align="center"
label="设备消耗"
width="60">
<template slot-scope="scope">
@ -211,9 +216,11 @@
:formatter="formatter"
prop="cert_expire_time"
label="证书到期时间"
align="center"
width="160">
</el-table-column>
<el-table-column
align="center"
prop="description"
label="备注"
>
@ -221,6 +228,7 @@
<el-table-column
fixed="right"
label="操作"
align="center"
width="150">
<template slot-scope="scope">
@ -322,38 +330,45 @@
style="width: 100%">
<el-table-column
fixed
align="center"
prop="device_udid"
label="设备ID"
>
</el-table-column>
<el-table-column
prop="device_name"
align="center"
label="设备名称"
width="120">
</el-table-column>
<el-table-column
prop="bundle_id"
align="center"
label="应用ID"
width="180">
</el-table-column>
<el-table-column
prop="bundle_name"
align="center"
label="应用名称"
width="160">
</el-table-column>
<el-table-column
prop="developer_id"
label="开发者ID"
align="center"
width="200">
</el-table-column>
<el-table-column
v-if="$store.state.userinfo&&$store.state.userinfo.role == 3"
prop="other_uid"
align="center"
label="被使用户uid">
</el-table-column>
<el-table-column
:formatter="deviceformatter"
prop="created_time"
align="center"
label="授权时间"
width="160">
</el-table-column>
@ -386,6 +401,7 @@
<el-table-column
fixed
align="center"
prop="udid"
label="设备ID"
>
@ -403,33 +419,39 @@
<el-table-column
prop="imei"
label="imei"
width="180">
align="center"
width="160">
</el-table-column>
<el-table-column
prop="product"
label="设备名称"
align="center"
width="100">
</el-table-column>
<el-table-column
prop="version"
label="设备型号"
align="center"
width="100">
</el-table-column>
<el-table-column
prop="serial"
label="设备序列号"
width="150">
align="center"
width="140">
</el-table-column>
<el-table-column
v-if="$store.state.userinfo&&$store.state.userinfo.role == 3"
prop="other_uid"
align="center"
label="被使用户uid">
</el-table-column>
<el-table-column
:formatter="deviceformatter"
prop="created_time"
label="添加时间"
align="center"
width="160">
</el-table-column>
<el-table-column
@ -445,10 +467,91 @@
@click="udidDeleteFun(scope)">删除
</el-button>
<el-tag v-else>
不允许操作
...
</el-tag>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="设备消耗账单" name="devicesbill">
<el-input
style="width: 30%;margin-right: 30px;margin-bottom: 10px"
v-model="udidsearch"
clearable
placeholder="输入UDID"/>
<el-button type="primary" icon="el-icon-search" @click="handleCurrentChange(pagination.currentPage)">
搜索
</el-button>
<el-table
:data="app_bill_lists"
v-loading="loading"
border
stripe
style="width: 100%">
<el-table-column
fixed
prop="udid"
align="center"
label="设备ID"
>
</el-table-column>
<el-table-column
prop="product"
label="设备名称"
align="center"
width="100">
</el-table-column>
<el-table-column
width="100"
prop="app_name"
align="center"
label="消费者"
>
</el-table-column>
<el-table-column
prop="remote_addr"
align="center"
label="客户端IP"
width="100">
</el-table-column>
<el-table-column
prop="action"
label="账单类型"
align="center"
width="100">
</el-table-column>
<el-table-column
prop="description"
label="备注"
align="center"
width="200">
</el-table-column>
<el-table-column
:formatter="deviceformatter"
align="center"
prop="created_time"
label="生成日期"
width="160">
</el-table-column>
<el-table-column
label="设备状态"
align="center"
width="110">
<template slot-scope="scope">
<el-tag v-if="scope.row.is_used===false" type="info">已经释放</el-tag>
<el-tag v-else>
使用中
</el-tag>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
@ -470,7 +573,7 @@
<script>
import {iosdeveloper, iosdevices, iosdevicesudid, developercert} from "@/restful";
import {iosdeveloper, iosdevices, iosdevicesudid, developercert, DeviceBillInfo} from "@/restful";
import {getUserInfoFun, removeAaary} from "@/utils";
export default {
@ -480,6 +583,7 @@
fileList: [],
app_developer_lists: [],
app_devices_lists: [],
app_bill_lists: [],
app_udid_lists: [],
activeName: "iosdeveloper",
udidsearch: "",
@ -693,7 +797,10 @@
// this.dialogaddDeveloperVisible=true;
} else if (tabname === "iosdeveloper") {
this.iosdeveloperFun({"methods": "GET", "data": data})
} else if (tabname === "devicesbill") {
this.iosdevicebillFun({"methods": "GET", "data": data})
}
},
// eslint-disable-next-line no-unused-vars
handleClick(tab, event) {
@ -780,6 +887,19 @@
}
}, params)
},
iosdevicebillFun(data) {
this.loading = true;
DeviceBillInfo(data => {
if (data.code === 1000) {
this.app_bill_lists = data.data;
this.pagination.total = data.count;
} else {
this.$message.error("操作失败了 " + data.msg);
}
this.loading = false
}, data)
},
iosdevicesudidFun(action, data, scope) {
if (action !== 'GET') {
this.loadingfun = this.$loading({

@ -692,3 +692,18 @@ export function advertinfo(callBack, params, load = true) {
true
);
}
/**签名账单 */
export function DeviceBillInfo(callBack, params, load = true) {
getData(
params.methods,
USERSEVER + '/supersign/bill',
params.data,
data => {
callBack(data);
},
load,
true,
true
);
}

@ -39,6 +39,7 @@ class Migration(migrations.Migration):
('udid_info', models.JSONField(blank=True, max_length=256, null=True, verbose_name='设备id信息')),
('developer_info', models.JSONField(blank=True, max_length=256, null=True, verbose_name='开发者信息')),
('description', models.CharField(blank=True, default='', max_length=128, verbose_name='操作描述')),
('remote_addr', models.GenericIPAddressField(verbose_name='远程IP地址')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='添加时间')),
('to_user_id', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE,
related_name='to_user_id', to=settings.AUTH_USER_MODEL,

@ -0,0 +1,26 @@
# Generated by Django 3.2.3 on 2021-11-03 14:25
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0017_developerappid_profile_id'),
]
operations = [
migrations.CreateModel(
name='DeviceQueue',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('udid', models.CharField(db_index=True, max_length=64, verbose_name='udid唯一标识')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='访问时间')),
('app_id',
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.apps', verbose_name='应用id')),
('developerid',
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.appiosdeveloperinfo',
verbose_name='所使用苹果开发者账户')),
],
),
]

@ -0,0 +1,17 @@
# Generated by Django 3.2.3 on 2021-11-03 17:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0018_devicequeue'),
]
operations = [
migrations.AddField(
model_name='iosdeveloperpublicpoolbill',
name='udid',
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='设备udid'),
),
]

@ -536,6 +536,7 @@ class IosDeveloperPublicPoolBill(models.Model):
number = models.IntegerField(verbose_name="消耗次数", default=1)
app_info = models.JSONField(max_length=256, verbose_name="属于哪个APP", null=True, blank=True)
udid_info = models.JSONField(max_length=256, verbose_name="设备id信息", null=True, blank=True)
udid = models.CharField(max_length=64, verbose_name="设备udid", null=True, blank=True)
developer_info = models.JSONField(max_length=256, verbose_name="开发者信息", null=True, blank=True)
udid_sync_info = models.ForeignKey(to="UDIDsyncDeveloper", on_delete=models.SET_NULL, verbose_name="关联同步设备信息",
null=True, blank=True)
@ -543,6 +544,7 @@ class IosDeveloperPublicPoolBill(models.Model):
# udid = models.ForeignKey(to="AppUDID", on_delete=models.CASCADE, verbose_name="所消耗的udid",null=True,blank=True)
# developerid = models.ForeignKey(to="AppIOSDeveloperInfo", on_delete=models.CASCADE, verbose_name="所使用苹果开发者账户",null=True,blank=True)
description = models.CharField(verbose_name="操作描述", max_length=128, default='', blank=True)
remote_addr = models.GenericIPAddressField(verbose_name="远程IP地址")
created_time = models.DateTimeField(auto_now_add=True, verbose_name="添加时间")
class Meta:
@ -568,3 +570,10 @@ class RemoteClientInfo(models.Model):
def __str__(self):
return "%s-%s" % (self.remote_addr, self.description)
class DeviceQueue(models.Model):
app_id = models.ForeignKey(to='Apps', on_delete=models.CASCADE, verbose_name="应用id")
udid = models.CharField(max_length=64, verbose_name="udid唯一标识", db_index=True)
developerid = models.ForeignKey(to="AppIOSDeveloperInfo", on_delete=models.CASCADE, verbose_name="所使用苹果开发者账户")
created_time = models.DateTimeField(auto_now_add=True, verbose_name="访问时间")

@ -28,7 +28,7 @@ def run_sign_task(format_udid_info, short, client_ip):
return '签名余额不足'
with cache.lock("%s_%s_%s" % ('run_sign_task', app_obj.app_id, ios_obj.developer_obj.issuer_id), timeout=60 * 10):
ios_obj.get_developer_auth()
status, msg = ios_obj.sign(client_ip)
status, msg = ios_obj.sign_ipa(client_ip)
if not status:
code = msg.get("code", -1)
if code == 0:

@ -25,7 +25,7 @@ from api.views.logout import LogoutView
from api.views.order import PriceView, OrderView, PaySuccess
from api.views.receiveudids import IosUDIDView, TaskView
from api.views.storage import StorageView
from api.views.supersign import DeveloperView, SuperSignUsedView, AppUDIDUsedView, SuperSignCertView
from api.views.supersign import DeveloperView, SuperSignUsedView, AppUDIDUsedView, SuperSignCertView, DeviceUsedBillView
from api.views.thirdlogin import ValidWxChatToken, ThirdWxAccount
from api.views.uploads import AppAnalyseView, UploadView
@ -56,6 +56,7 @@ urlpatterns = [
re_path("^supersign/devices$", SuperSignUsedView.as_view()),
re_path("^supersign/udid$", AppUDIDUsedView.as_view()),
re_path("^supersign/cert$", SuperSignCertView.as_view()),
re_path("^supersign/bill$", DeviceUsedBillView.as_view()),
re_path("^package_prices$", PriceView.as_view()),
re_path("^orders$", OrderView.as_view()),
re_path("^certification$", CertificationView.as_view()),

@ -205,16 +205,13 @@ def get_ios_developer_public_num(user_obj):
used_number = IosDeveloperPublicPoolBill.objects.filter(user_id=user_obj, action=0,
udid_sync_info__isnull=False).aggregate(
number=Sum('number'))
if add_number:
add_number = add_number.get("number", 0)
if not add_number:
return False
used_number = used_number.get("number", 0)
if not used_number:
used_number = 0
if add_number - used_number > 0:
return True
return False
add_number = add_number.get("number", 0)
if not add_number:
add_number = -99
used_number = used_number.get("number", 0)
if not used_number:
used_number = 0
return add_number - used_number
def get_developer_user_by_app_udid(user_obj, udid):
@ -234,25 +231,32 @@ def get_developer_user_by_app_udid(user_obj, udid):
for developer_obj in AppIOSDeveloperInfo.objects.filter(user_id=user_obj, is_actived=True,
certid__isnull=False).order_by("created_time"):
if get_developer_udided(developer_obj)[1] < developer_obj.usable_number:
return developer_obj
return None
return developer_obj
return developer_obj, False
return None, None
return developer_obj, True
def get_developer_obj_by_others(user_obj, udid):
result = get_developer_user_by_app_udid(user_obj, udid)
result, is_exist = get_developer_user_by_app_udid(user_obj, udid)
if result:
return result
if not get_ios_developer_public_num(user_obj):
return None
receive_user_obj_list = IosDeveloperPublicPoolBill.objects.filter(to_user_id=user_obj).all()
for receive_user_obj in receive_user_obj_list:
result = get_developer_user_by_app_udid(receive_user_obj.user_id, udid)
result, is_exist = get_developer_user_by_app_udid(receive_user_obj.user_id, udid)
if result is None:
continue
else:
logger.warning(f"user receive_user_obj {receive_user_obj.user_id} developer to sign")
return result
f_count = get_ios_developer_public_num(user_obj)
if not is_exist and f_count > 0:
logger.warning(f"user receive_user_obj {receive_user_obj.user_id} developer to sign")
return result
if is_exist:
if f_count > 0:
return result
if f_count == 0 and udid in [x.get('udid__udid__udid') for x in
APPSuperSignUsedInfo.objects.filter(user_id=user_obj).values(
'udid__udid__udid').all()]:
return result
return None
@ -453,7 +457,9 @@ class IosUtils(object):
developer_info=BillDeveloperInfoSerializer(
self.developer_obj).data,
udid_info=BillUdidInfoSerializer(udid_obj).data, action=0,
number=1, udid_sync_info=udid_sync_info
number=1, udid_sync_info=udid_sync_info,
remote_addr=client_ip,
udid=self.udid
)
@staticmethod
@ -511,13 +517,7 @@ class IosUtils(object):
d_result['msg'] = msg
return True, d_result
def sign(self, client_ip, sign_try_attempts=3):
"""
:param client_ip:
:param sign_try_attempts:
:return: status, result
:des: 仅用于苹果设备发送设备udid签名使用
"""
def check_sign_permission(self):
d_result = {'code': 0, 'msg': 'success'}
state, used_num = check_app_sign_limit(self.app_obj)
if not state:
@ -537,7 +537,19 @@ class IosUtils(object):
d_result['msg'] = msg
logger.error(d_result)
return False, d_result
return True, d_result
def sign_ipa(self, client_ip, sign_try_attempts=3):
"""
:param client_ip:
:param sign_try_attempts:
:return: status, result
:des: 仅用于苹果设备发送设备udid签名使用
"""
status, msg = self.check_sign_permission()
if not status:
return status, msg
d_result = {'code': 0, 'msg': 'success'}
app_udid_obj = AppUDID.objects.filter(app_id=self.app_obj, udid__udid=self.udid,
udid__developerid=self.developer_obj).first()
if app_udid_obj and app_udid_obj.is_download:

@ -727,3 +727,47 @@ class BillUdidInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.AppUDID
fields = ["pk", "app_id", "udid", "product", "serial", "version", "imei", "iccid"]
udid = serializers.SerializerMethodField()
def get_udid(self, obj):
return obj.udid.udid
class BillInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.IosDeveloperPublicPoolBill
exclude = ["user_id", "to_user_id", "developer_info", "app_info", "udid_sync_info"]
app_name = serializers.SerializerMethodField()
product = serializers.SerializerMethodField()
action = serializers.SerializerMethodField()
description = serializers.SerializerMethodField()
is_used = serializers.SerializerMethodField()
def get_is_used(self, obj):
if obj.udid_sync_info or obj.to_user_id:
return True
return False
def get_action(self, obj):
return get_choices_name_from_key(obj.action_choices, obj.action)
def get_app_name(self, obj):
if obj.app_info:
return obj.app_info.get('name')
elif obj.to_user_id:
return obj.user_id.first_name
def get_product(self, obj):
if obj.udid_info:
return obj.udid_info.get('product')
def get_description(self, obj):
if obj.udid_info:
return f"{self.get_app_name(obj)}-{self.get_action(obj)} -{obj.number} 设备数"
if obj.to_user_id:
if obj.to_user_id == self.context.get('user_obj'):
return f"{obj.user_id.first_name}-{self.get_action(obj)} +{obj.number} 设备数"
else:
return f"{obj.to_user_id.first_name} {self.get_action(obj)} -{obj.number} 设备数"

@ -75,20 +75,21 @@ def get_developer_devices(developer_obj_lists):
def get_captcha():
cptch_key = CaptchaStore.generate_key()
cptch_image = captcha_image_url(cptch_key)
captcha_key = CaptchaStore.generate_key()
captcha_image = captcha_image_url(captcha_key)
CaptchaStore.remove_expired()
local_storage = LocalStorage(**SERVER_DOMAIN.get("IOS_PMFILE_DOWNLOAD_DOMAIN"))
return {"cptch_image": "/".join([local_storage.get_base_url(), cptch_image.strip("/"), '']), "cptch_key": cptch_key,
return {"captcha_image": "/".join([local_storage.get_base_url(), captcha_image.strip("/"), '']),
"captcha_key": captcha_key,
"length": CAPTCHA_LENGTH}
def valid_captcha(cptch_key, code, username):
def valid_captcha(captcha_key, code, username):
if username:
challenge = CaptchaStore.objects.filter(hashkey=cptch_key).values("challenge").first()
logger.info(f"cptch_key:{cptch_key} code:{code} challenge:{challenge}")
challenge = CaptchaStore.objects.filter(hashkey=captcha_key).values("challenge").first()
logger.info(f"captcha_key:{captcha_key} code:{code} challenge:{challenge}")
if challenge:
if cptch_key and code and code.strip(" ").lower() == challenge.get("challenge").lower():
if captcha_key and code and code.strip(" ").lower() == challenge.get("challenge").lower():
return True
return False

@ -224,7 +224,7 @@ class AppInfoView(APIView):
# res.msg = "超级签余额不足,无法开启"
# return Response(res.dict)
developer_count = AppIOSDeveloperInfo.objects.filter(user_id=request.user).count()
if developer_count == 0 and not get_ios_developer_public_num(request.user):
if developer_count == 0 and get_ios_developer_public_num(request.user) < 0:
logger.error(f"app_id:{app_id} can't open super_sign,owner has no ios developer")
res.code = 1008
res.msg = "超级签余额不足,无法开启"

@ -5,16 +5,17 @@
# date: 2020/3/4
import logging
from django.db.models import Q
from django.http.response import FileResponse
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.views import APIView
from api.models import AppIOSDeveloperInfo, APPSuperSignUsedInfo, AppUDID
from api.models import AppIOSDeveloperInfo, APPSuperSignUsedInfo, AppUDID, IosDeveloperPublicPoolBill
from api.utils.app.supersignutils import IosUtils
from api.utils.auth import ExpiringTokenAuthentication, SuperSignPermission
from api.utils.response import BaseResponse
from api.utils.serializer import DeveloperSerializer, SuperSignUsedSerializer, DeviceUDIDSerializer
from api.utils.serializer import DeveloperSerializer, SuperSignUsedSerializer, DeviceUDIDSerializer, BillInfoSerializer
from api.utils.utils import get_developer_devices, get_choices_dict
logger = logging.getLogger(__name__)
@ -306,3 +307,23 @@ class SuperSignCertView(APIView):
res.msg = str(result['err_info'])
return Response(res.dict)
return Response(res.dict)
class DeviceUsedBillView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ]
permission_classes = [SuperSignPermission, ]
def get(self, request):
res = BaseResponse()
udid = request.query_params.get("udid", None)
page_obj = PageNumber()
user_used_list = IosDeveloperPublicPoolBill.objects.filter(Q(to_user_id=request.user) | Q(user_id=request.user))
if udid:
user_used_list = user_used_list.filter(udid=udid)
app_page_serializer = page_obj.paginate_queryset(queryset=user_used_list.order_by("-created_time"),
request=request,
view=self)
app_serializer = BillInfoSerializer(app_page_serializer, many=True, context={'user_obj': request.user})
res.data = app_serializer.data
res.count = user_used_list.count()
return Response(res.dict)

Loading…
Cancel
Save