From f8418f6414d98c24ac90b448774a7649547f783f Mon Sep 17 00:00:00 2001 From: MMXX Date: Fri, 17 Dec 2021 15:06:50 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=AD=BE=E5=90=8D=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E9=99=90=E9=A2=9D=20=E5=A2=9E=E5=8A=A0=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E7=AD=BE=E5=90=8D=E5=90=8E=E5=8C=85=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=20=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fir_client/src/components/FirBase.vue | 5 +- .../components/apps/FirAppInfossupersign.vue | 15 +++-- .../components/apps/FirAppInfostimeline.vue | 3 +- .../components/base/AppleDeveloperBindApp.vue | 60 +++++++++++++----- .../src/components/user/FirSuperSignBase.vue | 57 ++++++++++++++--- fir_client/vue.config.js | 2 +- ...27_appiosdeveloperinfo_app_limit_number.py | 17 +++++ fir_ser/api/models.py | 7 +++ fir_ser/api/utils/app/supersignutils.py | 32 +++++++--- fir_ser/api/utils/serializer.py | 17 ++++- fir_ser/api/utils/storage/caches.py | 47 +++++++++++++- fir_ser/api/views/download.py | 48 ++------------ fir_ser/api/views/supersign.py | 62 +++++++++++++++++-- 13 files changed, 280 insertions(+), 92 deletions(-) create mode 100644 fir_ser/api/migrations/0027_appiosdeveloperinfo_app_limit_number.py diff --git a/fir_client/src/components/FirBase.vue b/fir_client/src/components/FirBase.vue index 7fd2c6f..55622e7 100644 --- a/fir_client/src/components/FirBase.vue +++ b/fir_client/src/components/FirBase.vue @@ -19,7 +19,7 @@ type="error">
应用分发请绑定您自己的域名,平台分发域名可能因不可违因素更换,将导致您的应用无法访问 - 立即绑定 + 立即绑定
@@ -125,4 +125,7 @@ export default { font-size: medium; margin-right: 20px; } +/deep/ .el-alert{ + padding: 2px 16px; +} diff --git a/fir_client/src/components/apps/FirAppInfossupersign.vue b/fir_client/src/components/apps/FirAppInfossupersign.vue index 7953daa..2cc6a81 100644 --- a/fir_client/src/components/apps/FirAppInfossupersign.vue +++ b/fir_client/src/components/apps/FirAppInfossupersign.vue @@ -1,7 +1,7 @@ @@ -432,6 +445,11 @@ + 该开发者可以可消耗设备数量,超过该数量,将无法进行新设备签名 + + + + 该开发者可以签名应用数量,超过该数量,将无法进行新应用签名 @@ -593,6 +611,14 @@ label="应用名称" prop="bundle_name" width="160"> + { + 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 } diff --git a/fir_client/vue.config.js b/fir_client/vue.config.js index 8345a2c..f72191c 100644 --- a/fir_client/vue.config.js +++ b/fir_client/vue.config.js @@ -82,7 +82,7 @@ if (page) { } } -const version='1.3.6'; +const version='1.3.7'; const pro_base_env = { baseUrl: 'https://flyapps.cn', diff --git a/fir_ser/api/migrations/0027_appiosdeveloperinfo_app_limit_number.py b/fir_ser/api/migrations/0027_appiosdeveloperinfo_app_limit_number.py new file mode 100644 index 0000000..294f65f --- /dev/null +++ b/fir_ser/api/migrations/0027_appiosdeveloperinfo_app_limit_number.py @@ -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'), + ), + ] diff --git a/fir_ser/api/models.py b/fir_ser/api/models.py index a1ff987..7eebab1 100644 --- a/fir_ser/api/models.py +++ b/fir_ser/api/models.py @@ -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): diff --git a/fir_ser/api/utils/app/supersignutils.py b/fir_ser/api/utils/app/supersignutils.py index 43328db..d40db53 100644 --- a/fir_ser/api/utils/app/supersignutils.py +++ b/fir_ser/api/utils/app/supersignutils.py @@ -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: - can_used_developer_pk_list.append(developer_obj.pk) + 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 diff --git a/fir_ser/api/utils/serializer.py b/fir_ser/api/utils/serializer.py index b0d1fd5..16b6611 100644 --- a/fir_ser/api/utils/serializer.py +++ b/fir_ser/api/utils/serializer.py @@ -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() diff --git a/fir_ser/api/utils/storage/caches.py b/fir_ser/api/utils/storage/caches.py index 04b9f7d..59b3da8 100644 --- a/fir_ser/api/utils/storage/caches.py +++ b/fir_ser/api/utils/storage/caches.py @@ -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 diff --git a/fir_ser/api/views/download.py b/fir_ser/api/views/download.py index 353b407..1d1ec5a 100644 --- a/fir_ser/api/views/download.py +++ b/fir_ser/api/views/download.py @@ -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) diff --git a/fir_ser/api/views/supersign.py b/fir_ser/api/views/supersign.py index db23ad7..1d42c4a 100644 --- a/fir_ser/api/views/supersign.py +++ b/fir_ser/api/views/supersign.py @@ -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,9 +535,19 @@ 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: - many_obj.append(AppleDeveloperToAppUse(developerid=developer_obj, app_id=app_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() if issuer_id: @@ -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: - many_obj.append(AppleDeveloperToAppUse(developerid=developer_obj, app_id=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()