优化代码,增加苹果api访问代理

存储迁移只允许读操作
qrnn
youngS 4 years ago
parent 49c35275b6
commit 26e6efeaf4
  1. 32
      fir_client/src/components/apps/FirApps.vue
  2. 50
      fir_client/src/components/user/FirUserStorage.vue
  3. 14
      fir_client/src/restful/index.js
  4. 5
      fir_client/src/utils/index.js
  5. 6
      fir_ser/api/base_views.py
  6. 6
      fir_ser/api/tasks.py
  7. 3
      fir_ser/api/urls.py
  8. 30
      fir_ser/api/utils/app/apputils.py
  9. 28
      fir_ser/api/utils/app/iossignapi.py
  10. 4
      fir_ser/api/utils/app/supersignutils.py
  11. 56
      fir_ser/api/utils/apple/appleapiv3.py
  12. 33
      fir_ser/api/utils/storage/caches.py
  13. 36
      fir_ser/api/views/apps.py
  14. 48
      fir_ser/api/views/storage.py
  15. 21
      fir_ser/api/views/supersign.py
  16. 26
      fir_ser/api/views/uploads.py
  17. 6
      fir_ser/config.py
  18. 6
      fir_ser/fir_ser/settings.py

@ -144,7 +144,7 @@
</el-table> </el-table>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button plain @click="closeUpload"> </el-button> <el-button :disabled="multiuploaddisable" plain @click="closeUpload"> </el-button>
<el-button :disabled="multiuploaddisable" plain type="primary" <el-button :disabled="multiuploaddisable" plain type="primary"
@click="multiuploadFun">开始上传</el-button> @click="multiuploadFun">开始上传</el-button>
</span> </span>
@ -609,6 +609,7 @@ export default {
multiupload: false, multiupload: false,
multiuploaddisable: false, multiuploaddisable: false,
multiFileList: [], multiFileList: [],
trymultiFileList: [],
default_pay_radio: '', default_pay_radio: '',
default_price_radio: '', default_price_radio: '',
pay_choices: [], pay_choices: [],
@ -657,7 +658,7 @@ export default {
"app_id": short "app_id": short
}) })
}, },
multirun(process, keylist, func) { multirun(process, keylist, func, failback) {
let thr = []; let thr = [];
for (let i = 0; i < process; i++) { for (let i = 0; i < process; i++) {
thr.push(Promise.resolve()) thr.push(Promise.resolve())
@ -671,7 +672,10 @@ export default {
} }
} }
if (failback) {
// eslint-disable-next-line no-unused-vars
thr[process - 1].then(_ => failback())
}
}, },
uploadasync(file) { uploadasync(file) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -703,7 +707,9 @@ export default {
} else { } else {
this.$message.error("应用 " + analyseappinfo.appname + " 上传token获取失败,请刷新重试") this.$message.error("应用 " + analyseappinfo.appname + " 上传token获取失败,请刷新重试")
this.multiFileList.splice(this.multiFileList.indexOf(file), 1) resolve()
this.trymultiFileList.push(file);
// this.multiFileList.splice(this.multiFileList.indexOf(file), 1)
} }
loading.close(); loading.close();
}, { }, {
@ -713,12 +719,16 @@ export default {
} else { } else {
this.$message.error("文件 " + file.raw.name + " 解析失败,请检查是否为APP应用") this.$message.error("文件 " + file.raw.name + " 解析失败,请检查是否为APP应用")
this.multiFileList.splice(this.multiFileList.indexOf(file), 1) resolve()
this.trymultiFileList.push(file);
// this.multiFileList.splice(this.multiFileList.indexOf(file), 1)
} }
}, err => { }, err => {
loading.close(); loading.close();
this.$message.error("应用解析失败,请检查是否为APP应用"); this.$message.error("应用解析失败,请检查是否为APP应用");
this.multiFileList.splice(this.multiFileList.indexOf(file), 1) resolve()
this.trymultiFileList.push(file);
// this.multiFileList.splice(this.multiFileList.indexOf(file), 1)
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log('Error ', err); console.log('Error ', err);
}); });
@ -731,8 +741,16 @@ export default {
multiuploadFun() { multiuploadFun() {
this.multiuploaddisable = true; this.multiuploaddisable = true;
if (this.multiFileList && this.multiFileList.length > 0) { if (this.multiFileList && this.multiFileList.length > 0) {
this.multirun(3, this.multiFileList, this.uploadasync) // eslint-disable-next-line no-unused-vars
this.multirun(3, this.multiFileList, this.uploadasync, _ => {
// eslint-disable-next-line no-console
console.log('upload file ' + this.trymultiFileList.length + ' failed. try again')
if (this.trymultiFileList && this.trymultiFileList.length > 0) {
this.multirun(3, this.trymultiFileList, this.uploadasync, null)
}
})
} }
}, },
show_package_prices() { show_package_prices() {
get_package_prices(res => { get_package_prices(res => {

@ -101,6 +101,18 @@
强制迁移忽略数据迁移失败错误可能会导致数据丢失 强制迁移忽略数据迁移失败错误可能会导致数据丢失
</el-button> </el-button>
</div> </div>
<div v-else style="margin-top: 20px">
<el-button round style="margin-left: 10px"
type="danger"
@click="clean_storage_data('all')">
清理所有app数据
</el-button>
<el-button round style="margin-left: 10px"
type="danger"
@click="clean_storage_data('history')">
清理app历史版本数据只保留最新数据
</el-button>
</div>
<el-divider/> <el-divider/>
<el-form v-if="storageinfo.id && storageinfo.id !==-1" ref="storageinfoform" :model="storageinfo" <el-form v-if="storageinfo.id && storageinfo.id !==-1" ref="storageinfoform" :model="storageinfo"
label-width="80px" style="width: 39%;margin:0 auto;"> label-width="80px" style="width: 39%;margin:0 auto;">
@ -308,7 +320,7 @@
</template> </template>
<script> <script>
import {getStorageinfo} from "@/restful"; import {cleanStorageData, getStorageinfo} from "@/restful";
import {deepCopy, getUserInfoFun} from "@/utils"; import {deepCopy, getUserInfoFun} from "@/utils";
export default { export default {
@ -394,6 +406,42 @@ export default {
}); });
}, },
validFun(val) {
if (val && val.length > 6) {
return true
}
return false
},
clean_storage_data(act) {
this.$prompt('此操作属于危险操作,请悉知你操作将导致的影响,输入登录密码进行确认该操作', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPlaceholder: '该用户的登录密码',
inputValidator: this.validFun
}).then(({value}) => {
const loading = this.$loading({
lock: true,
text: '执行中,请耐心等待...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
cleanStorageData(data => {
loading.close();
if (data.code === 1000) {
this.$message.success('清理成功');
} else {
this.$message.error(data.msg)
}
}, {"methods": 'POST', 'data': {'act': act, 'confirm_pwd': value}});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消操作'
});
});
},
change_storage_info(force) { change_storage_info(force) {
this.$confirm('此操作将导致应用,图片,显示下载异常, 是否继续?', '警告', { this.$confirm('此操作将导致应用,图片,显示下载异常, 是否继续?', '警告', {
confirmButtonText: '确定', confirmButtonText: '确定',

@ -388,6 +388,20 @@ export function getStorageinfo(callBack, params, load = true) {
); );
} }
/**用户app清理操作 */
export function cleanStorageData(callBack, params, load = true) {
getData(
params.methods,
USERSEVER + '/storage/clean',
params.data,
data => {
callBack(data);
},
load,
true,
true
);
}
/**用户个人信息 */ /**用户个人信息 */
export function userinfos(callBack, params, load = true) { export function userinfos(callBack, params, load = true) {

@ -217,7 +217,10 @@ export function uploadaliyunoss(file, certinfo, app, successcallback, processcal
retryCount++; retryCount++;
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error("retryCount : " + retryCount); console.error("retryCount : " + retryCount);
uploadFile('') // eslint-disable-next-line no-unused-vars
setTimeout(_ => {
uploadFile('')
}, 1000);
} else { } else {
app.$message({ app.$message({
message: file.name + ' 重试了' + retryCount + '次,还是上传失败了,请刷新页面重试', message: file.name + ' 重试了' + retryCount + '次,还是上传失败了,请刷新页面重试',

@ -25,6 +25,11 @@ def app_delete(app_obj):
res.msg = "应用不存在" res.msg = "应用不存在"
return res return res
user_obj = app_obj.user_id user_obj = app_obj.user_id
if MigrateStorageState(user_obj.uid).get_state():
res.code = 1001
res.msg = "数据迁移中"
return res
count = APPToDeveloper.objects.filter(app_id=app_obj).count() count = APPToDeveloper.objects.filter(app_id=app_obj).count()
if app_obj.issupersign or count > 0: if app_obj.issupersign or count > 0:
logger.info(f"app_id:{app_obj.app_id} is supersign ,delete this app need clean IOS developer") logger.info(f"app_id:{app_obj.app_id} is supersign ,delete this app need clean IOS developer")
@ -127,5 +132,4 @@ def storage_change(use_storage_id, user_obj, force):
else: else:
return False return False
del_cache_storage(user_obj) del_cache_storage(user_obj)
MigrateStorageState.del_state(user_obj.uid)
return True return True

@ -15,6 +15,7 @@ from api.utils.crontab.ctasks import sync_download_times, auto_clean_upload_tmp_
auto_check_ios_developer_active auto_check_ios_developer_active
from api.utils.geetest.geetest_utils import check_bypass_status from api.utils.geetest.geetest_utils import check_bypass_status
from api.utils.mp.wechat import sync_wx_access_token from api.utils.mp.wechat import sync_wx_access_token
from api.utils.storage.caches import MigrateStorageState
from api.utils.storage.storage import get_local_storage from api.utils.storage.storage import get_local_storage
from api.views.login import get_login_type from api.views.login import get_login_type
from fir_ser.celery import app from fir_ser.celery import app
@ -26,6 +27,11 @@ logger = logging.getLogger(__name__)
@shared_task @shared_task
def run_sign_task(format_udid_info, short, client_ip): def run_sign_task(format_udid_info, short, client_ip):
app_obj = Apps.objects.filter(short=short).first() app_obj = Apps.objects.filter(short=short).first()
if MigrateStorageState(app_obj.user_id.uid).get_state():
msg = "数据迁移中,无法处理该操作"
return msg
ios_obj = IosUtils(format_udid_info, app_obj.user_id, app_obj) ios_obj = IosUtils(format_udid_info, app_obj.user_id, app_obj)
status, msg = ios_obj.sign_ipa(client_ip) status, msg = ios_obj.sign_ipa(client_ip)
if not status: if not status:

@ -25,7 +25,7 @@ from api.views.logout import LogoutView
from api.views.order import PriceView, OrderView, PaySuccess from api.views.order import PriceView, OrderView, PaySuccess
from api.views.receiveudids import IosUDIDView, TaskView from api.views.receiveudids import IosUDIDView, TaskView
from api.views.report import ReportView from api.views.report import ReportView
from api.views.storage import StorageView from api.views.storage import StorageView, CleanStorageView
from api.views.supersign import DeveloperView, SuperSignUsedView, AppUDIDUsedView, SuperSignCertView, \ from api.views.supersign import DeveloperView, SuperSignUsedView, AppUDIDUsedView, SuperSignCertView, \
DeviceUsedBillView, DeveloperDeviceView, DeviceUsedRankInfoView DeviceUsedBillView, DeveloperDeviceView, DeviceUsedRankInfoView
from api.views.thirdlogin import ValidWxChatToken, ThirdWxAccount from api.views.thirdlogin import ValidWxChatToken, ThirdWxAccount
@ -44,6 +44,7 @@ urlpatterns = [
re_path("^logout", LogoutView.as_view()), re_path("^logout", LogoutView.as_view()),
re_path("^apps$", AppsView.as_view()), re_path("^apps$", AppsView.as_view()),
re_path("^storage$", StorageView.as_view()), re_path("^storage$", StorageView.as_view()),
re_path("^storage/clean$", CleanStorageView.as_view()),
re_path(r"^apps/(?P<app_id>\w+)", AppInfoView.as_view()), re_path(r"^apps/(?P<app_id>\w+)", AppInfoView.as_view()),
re_path(r"^appinfos/(?P<app_id>\w+)/(?P<act>\w+)", AppReleaseInfoView.as_view()), re_path(r"^appinfos/(?P<app_id>\w+)/(?P<act>\w+)", AppReleaseInfoView.as_view()),
re_path("^upload$", UploadView.as_view()), re_path("^upload$", UploadView.as_view()),

@ -9,7 +9,7 @@ import random
from api.models import AppReleaseInfo, Apps from api.models import AppReleaseInfo, Apps
from api.utils.baseutils import make_app_uuid from api.utils.baseutils import make_app_uuid
from api.utils.modelutils import get_user_domain_name from api.utils.modelutils import get_user_domain_name
from api.utils.storage.caches import del_cache_response_by_short from api.utils.storage.caches import del_cache_response_by_short, MigrateStorageState
from api.utils.storage.storage import Storage from api.utils.storage.storage import Storage
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -114,6 +114,22 @@ def get_random_short(number=4):
return short_url return short_url
def clean_history_apps(app_obj, user_obj, history_release_limit=20):
storage_obj = Storage(user_obj)
if not MigrateStorageState(user_obj.uid).get_state():
release_queryset = AppReleaseInfo.objects.filter(app_id=app_obj).order_by("-created_time")
if release_queryset.count() > history_release_limit:
flag = 0
for release_obj in release_queryset:
flag += 1
if flag > history_release_limit:
logger.info(
f"history_release_limit:{history_release_limit} this release is to more,so delete it release_id:{release_obj.release_id}")
storage_obj.delete_file(release_obj.release_id, app_obj.type)
storage_obj.delete_file(release_obj.icon_url)
release_obj.delete()
def save_app_infos(app_file_name, user_obj, app_info, bundle_id, app_img, short, size, issupersign): def save_app_infos(app_file_name, user_obj, app_info, bundle_id, app_img, short, size, issupersign):
app_uuid = make_app_uuid(user_obj, bundle_id + app_file_name.split(".")[1]) app_uuid = make_app_uuid(user_obj, bundle_id + app_file_name.split(".")[1])
##判断是否存在该app ##判断是否存在该app
@ -193,15 +209,5 @@ def save_app_infos(app_file_name, user_obj, app_info, bundle_id, app_img, short,
return True return True
if history_release_limit != 0: if history_release_limit != 0:
release_queryset = AppReleaseInfo.objects.filter(app_id=app_obj).order_by("-created_time") clean_history_apps(app_obj, user_obj, history_release_limit)
if release_queryset.count() > history_release_limit:
flag = 0
for release_obj in release_queryset:
flag += 1
if flag > history_release_limit:
logger.info(
f"history_release_limit:{history_release_limit} this release is to more,so delete it release_id:{release_obj.release_id}")
storage.delete_file(release_obj.release_id, app_obj.type)
storage.delete_file(release_obj.icon_url)
release_obj.delete()
return True return True

@ -327,9 +327,11 @@ class AppDeveloperApiV2(object):
logger.error("ios developer set devices status Failed Exception:%s" % e) logger.error("ios developer set devices status Failed Exception:%s" % e)
result['return_info'] = "%s" % e result['return_info'] = "%s" % e
if device_err_callback and ("There are no current ios devices" in str(e) or "Device obj is None" in str(e)): if device_err_callback and ("There are no current ios devices" in str(e) or "Device obj is None" in str(e)):
CleanErrorBundleIdSignDataState.set_state(failed_call_prefix) with CleanErrorBundleIdSignDataState(failed_call_prefix) as state:
device_err_callback() if state:
CleanErrorBundleIdSignDataState.del_state(failed_call_prefix) device_err_callback()
else:
logger.warning(f'{device_err_callback}-{failed_call_prefix} is running')
return False, result return False, result
def get_device(self): def get_device(self):
@ -391,9 +393,13 @@ class AppDeveloperApiV2(object):
logger.error("ios developer register device Failed Exception:%s" % e) logger.error("ios developer register device Failed Exception:%s" % e)
result['return_info'] = "%s" % e result['return_info'] = "%s" % e
if device_err_callback and "There are no current ios devices" in str(e): if device_err_callback and "There are no current ios devices" in str(e):
CleanErrorBundleIdSignDataState.set_state(failed_call_prefix)
device_err_callback() with CleanErrorBundleIdSignDataState(failed_call_prefix) as state:
CleanErrorBundleIdSignDataState.del_state(failed_call_prefix) if state:
device_err_callback()
else:
logger.warning(f'{device_err_callback}-{failed_call_prefix} is running')
return False, result return False, result
def make_and_download_profile(self, app_obj, provision_name, auth, developer_app_id, device_id_list, profile_id, def make_and_download_profile(self, app_obj, provision_name, auth, developer_app_id, device_id_list, profile_id,
@ -418,10 +424,12 @@ class AppDeveloperApiV2(object):
logger.error(f"app_id {app_obj.app_id} ios developer make profile Failed Exception:{e}") logger.error(f"app_id {app_obj.app_id} ios developer make profile Failed Exception:{e}")
result['return_info'] = "%s" % e result['return_info'] = "%s" % e
if app_id_err_callback and "There is no App ID with ID" in str(e): if app_id_err_callback and "There is no App ID with ID" in str(e):
CleanErrorBundleIdSignDataState.set_state(failed_call_prefix) with CleanErrorBundleIdSignDataState(failed_call_prefix) as state:
for call_fun in app_id_err_callback: if state:
call_fun() for call_fun in app_id_err_callback:
CleanErrorBundleIdSignDataState.del_state(failed_call_prefix) call_fun()
else:
logger.warning(f'{app_id_err_callback}-{failed_call_prefix} is running')
return False, result return False, result
def modify_capability(self, app_obj, developer_app_id): def modify_capability(self, app_obj, developer_app_id):

@ -52,7 +52,7 @@ def resign_by_app_id_and_developer(app_id, developer_id, developer_app_id, need_
if check_ipa_is_latest_sign(app_obj, developer_obj) and not force: if check_ipa_is_latest_sign(app_obj, developer_obj) and not force:
return return
add_new_bundles_prefix = f"check_or_add_new_bundles_{developer_obj.issuer_id}_{app_obj.app_id}" add_new_bundles_prefix = f"check_or_add_new_bundles_{developer_obj.issuer_id}_{app_obj.app_id}"
if CleanErrorBundleIdSignDataState.get_state(add_new_bundles_prefix): if CleanErrorBundleIdSignDataState(add_new_bundles_prefix).get_state():
return False, '清理执行中,请等待' return False, '清理执行中,请等待'
d_time = time.time() d_time = time.time()
if need_download_profile: if need_download_profile:
@ -664,7 +664,7 @@ class IosUtils(object):
download_profile_prefix = f"make_and_download_profile_{self.developer_obj.issuer_id}_{self.app_obj.app_id}" download_profile_prefix = f"make_and_download_profile_{self.developer_obj.issuer_id}_{self.app_obj.app_id}"
with cache.lock(register_devices_prefix, timeout=60): with cache.lock(register_devices_prefix, timeout=60):
if CleanErrorBundleIdSignDataState.get_state(add_new_bundles_prefix): if CleanErrorBundleIdSignDataState(add_new_bundles_prefix).get_state():
return True, True # 程序错误,进行清理的时候,拦截多余的设备注册 return True, True # 程序错误,进行清理的时候,拦截多余的设备注册
if not get_developer_obj_by_others(self.user_obj, self.udid, self.app_obj): if not get_developer_obj_by_others(self.user_obj, self.udid, self.app_obj):
d_result['code'] = 1005 d_result['code'] = 1005

@ -15,14 +15,19 @@ from functools import wraps
import jwt import jwt
import requests import requests
from django.conf import settings
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api # https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api
# https://appstoreconnect.apple.com/access/api 去申请秘钥 # https://appstoreconnect.apple.com/access/api 去申请秘钥
# #
proxies = settings.APPLE_DEVELOPER_API_PROXY if settings.APPLE_DEVELOPER_API_PROXY else {}
timeout = settings.APPLE_DEVELOPER_API_TIMEOUT if settings.APPLE_DEVELOPER_API_TIMEOUT else 180
def request_format_log(req): def request_format_log(req):
try: try:
logger.info(f"url:{req.url} header:{req.headers} code:{req.status_code} body:{req.content}") logger.info(f"url:{req.url} header:{req.headers} code:{req.status_code} body:{req.content}")
@ -93,7 +98,8 @@ class DevicesAPI(object):
if query_parameters: if query_parameters:
for k, v in query_parameters.items(): for k, v in query_parameters.items():
params[k] = v params[k] = v
return request_format_log(requests.get(self.devices_url, params=params, headers=self.headers)) return request_format_log(
requests.get(self.devices_url, params=params, headers=self.headers, proxies=proxies, timeout=timeout))
def list_enabled_devices(self): def list_enabled_devices(self):
return self.list_devices({"filter[status]": "ENABLED"}) return self.list_devices({"filter[status]": "ENABLED"})
@ -126,7 +132,8 @@ class DevicesAPI(object):
} }
} }
} }
return request_format_log(requests.post(self.devices_url, json=json, headers=self.headers)) return request_format_log(
requests.post(self.devices_url, json=json, headers=self.headers, proxies=proxies, timeout=timeout))
def read_device_information(self, device_id): def read_device_information(self, device_id):
""" """
@ -141,7 +148,8 @@ class DevicesAPI(object):
params = { params = {
"fields[devices]": "addedDate, deviceClass, model, name, platform, status, udid", "fields[devices]": "addedDate, deviceClass, model, name, platform, status, udid",
} }
return request_format_log(requests.get(base_url, params=params, headers=self.headers)) return request_format_log(
requests.get(base_url, params=params, headers=self.headers, proxies=proxies, timeout=timeout))
def enabled_device(self, device_id, device_name): def enabled_device(self, device_id, device_name):
return self.modify_registered_device(device_id, device_name, 'ENABLED') return self.modify_registered_device(device_id, device_name, 'ENABLED')
@ -172,7 +180,8 @@ class DevicesAPI(object):
} }
} }
} }
return request_format_log(requests.patch(base_url, json=json, headers=self.headers)) return request_format_log(
requests.patch(base_url, json=json, headers=self.headers, proxies=proxies, timeout=timeout))
class BundleIDsAPI(object): class BundleIDsAPI(object):
@ -204,7 +213,8 @@ class BundleIDsAPI(object):
} }
} }
} }
return request_format_log(requests.post(self.bundle_ids_url, json=json, headers=self.headers)) return request_format_log(
requests.post(self.bundle_ids_url, json=json, headers=self.headers, proxies=proxies, timeout=timeout))
def delete_bundle_id_by_id(self, bundle_id): def delete_bundle_id_by_id(self, bundle_id):
""" """
@ -218,7 +228,8 @@ class BundleIDsAPI(object):
""" """
base_url = '%s/%s' % (self.bundle_ids_url, bundle_id) base_url = '%s/%s' % (self.bundle_ids_url, bundle_id)
json = {} json = {}
return request_format_log(requests.delete(base_url, json=json, headers=self.headers)) return request_format_log(
requests.delete(base_url, json=json, headers=self.headers, proxies=proxies, timeout=timeout))
def list_bundle_ids(self, query_parameters=None): def list_bundle_ids(self, query_parameters=None):
""" """
@ -236,7 +247,8 @@ class BundleIDsAPI(object):
if query_parameters: if query_parameters:
for k, v in query_parameters.items(): for k, v in query_parameters.items():
params[k] = v params[k] = v
return request_format_log(requests.get(self.bundle_ids_url, params=params, headers=self.headers)) return request_format_log(
requests.get(self.bundle_ids_url, params=params, headers=self.headers, proxies=proxies, timeout=timeout))
def list_bundle_id_by_identifier(self, identifier): def list_bundle_id_by_identifier(self, identifier):
return self.list_bundle_ids({"filter[identifier]": identifier}) return self.list_bundle_ids({"filter[identifier]": identifier})
@ -265,7 +277,8 @@ class BundleIDsAPI(object):
} }
} }
} }
return request_format_log(requests.patch(base_url, json=json, headers=self.headers)) return request_format_log(
requests.patch(base_url, json=json, headers=self.headers, proxies=proxies, timeout=timeout))
class BundleIDsCapabilityAPI(object): class BundleIDsCapabilityAPI(object):
@ -287,7 +300,8 @@ class BundleIDsCapabilityAPI(object):
""" """
base_url = '%s/%s_%s' % (self.bundle_ids_capability_url, bundle_id, capability_type) base_url = '%s/%s_%s' % (self.bundle_ids_capability_url, bundle_id, capability_type)
json = {} json = {}
return request_format_log(requests.delete(base_url, json=json, headers=self.headers)) return request_format_log(
requests.delete(base_url, json=json, headers=self.headers, proxies=proxies, timeout=timeout))
def enable_capability(self, bundle_id, capability_type): def enable_capability(self, bundle_id, capability_type):
""" """
@ -316,7 +330,9 @@ class BundleIDsCapabilityAPI(object):
} }
} }
} }
return request_format_log(requests.post(self.bundle_ids_capability_url, json=json, headers=self.headers)) return request_format_log(
requests.post(self.bundle_ids_capability_url, json=json, headers=self.headers, proxies=proxies,
timeout=timeout))
class ProfilesAPI(object): class ProfilesAPI(object):
@ -368,7 +384,8 @@ class ProfilesAPI(object):
} }
} }
} }
return request_format_log(requests.post(self.profiles_url, json=json, headers=self.headers)) return request_format_log(
requests.post(self.profiles_url, json=json, headers=self.headers, proxies=proxies, timeout=timeout))
def delete_profile(self, profile_id): def delete_profile(self, profile_id):
""" """
@ -382,7 +399,8 @@ class ProfilesAPI(object):
""" """
base_url = '%s/%s' % (self.profiles_url, profile_id) base_url = '%s/%s' % (self.profiles_url, profile_id)
json = {} json = {}
return request_format_log(requests.delete(base_url, json=json, headers=self.headers)) return request_format_log(
requests.delete(base_url, json=json, headers=self.headers, proxies=proxies, timeout=timeout))
def download_profile(self, profile_id): def download_profile(self, profile_id):
# n=base64.b64decode(profileContent) # n=base64.b64decode(profileContent)
@ -407,7 +425,8 @@ class ProfilesAPI(object):
if query_parameters: if query_parameters:
for k, v in query_parameters.items(): for k, v in query_parameters.items():
params[k] = v params[k] = v
return request_format_log(requests.get(self.profiles_url, params=params, headers=self.headers)) return request_format_log(
requests.get(self.profiles_url, params=params, headers=self.headers, proxies=proxies, timeout=timeout))
def list_profile_by_profile_id(self, profile_id): def list_profile_by_profile_id(self, profile_id):
return self.list_profiles({"filter[id]": profile_id, "include": ""}) return self.list_profiles({"filter[id]": profile_id, "include": ""})
@ -442,7 +461,8 @@ class CertificatesAPI(object):
} }
} }
} }
return request_format_log(requests.post(self.certificates_url, json=json, headers=self.headers)) return request_format_log(
requests.post(self.certificates_url, json=json, headers=self.headers, proxies=proxies, timeout=timeout))
def download_certificate(self, certificate_id): def download_certificate(self, certificate_id):
# req.json()['data'][0]['attributes']['certificateContent'] # req.json()['data'][0]['attributes']['certificateContent']
@ -467,7 +487,8 @@ class CertificatesAPI(object):
if query_parameters: if query_parameters:
for k, v in query_parameters.items(): for k, v in query_parameters.items():
params[k] = v params[k] = v
return request_format_log(requests.get(self.certificates_url, params=params, headers=self.headers)) return request_format_log(
requests.get(self.certificates_url, params=params, headers=self.headers, proxies=proxies, timeout=timeout))
def list_certificate_by_certificate_id(self, certificate_id): def list_certificate_by_certificate_id(self, certificate_id):
return self.list_certificate({"filter[id]": certificate_id, }) return self.list_certificate({"filter[id]": certificate_id, })
@ -484,7 +505,8 @@ class CertificatesAPI(object):
""" """
base_url = '%s/%s' % (self.certificates_url, certificate_id) base_url = '%s/%s' % (self.certificates_url, certificate_id)
json = {} json = {}
return request_format_log(requests.delete(base_url, json=json, headers=self.headers)) return request_format_log(
requests.delete(base_url, json=json, headers=self.headers, proxies=proxies, timeout=timeout))
class BaseInfoObj(object): class BaseInfoObj(object):

@ -514,18 +514,27 @@ def get_wx_ticket_login_info_cache(ticket):
class CacheBaseState(object): class CacheBaseState(object):
@classmethod def __init__(self, key, value=time.time(), timeout=3600 * 24):
def get_state(cls, key): self.key = f"CacheBaseState_{self.__class__.__name__}_{key}"
return cache.get(f"{cls.__name__}_{key}") self.value = value
self.timeout = timeout
@classmethod self.active = False
def set_state(cls, key, value=time.time(), timeout=3600 * 24):
cls.del_state(f"{cls.__name__}_{key}") def get_state(self):
cache.set(f"{cls.__name__}_{key}", value, timeout) return cache.get(self.key)
@classmethod def __enter__(self):
def del_state(cls, key): if cache.get(self.key):
cache.delete(f"{cls.__name__}_{key}") return False
else:
cache.set(self.key, self.value, self.timeout)
self.active = True
return True
def __exit__(self, exc_type, exc_val, exc_tb):
if self.active:
cache.delete(self.key)
logger.info(f"cache base state __exit__ {exc_type}, {exc_val}, {exc_tb}")
class MigrateStorageState(CacheBaseState): class MigrateStorageState(CacheBaseState):

@ -20,7 +20,7 @@ from api.utils.modelutils import get_user_domain_name, get_app_domain_name, chec
from api.utils.response import BaseResponse from api.utils.response import BaseResponse
from api.utils.serializer import AppsSerializer, AppReleaseSerializer, AppsListSerializer from api.utils.serializer import AppsSerializer, AppReleaseSerializer, AppsListSerializer
from api.utils.storage.caches import del_cache_response_by_short, get_app_today_download_times, del_cache_by_delete_app, \ from api.utils.storage.caches import del_cache_response_by_short, get_app_today_download_times, del_cache_by_delete_app, \
CleanAppSignDataState CleanAppSignDataState, MigrateStorageState
from api.utils.storage.storage import Storage from api.utils.storage.storage import Storage
from api.utils.utils import delete_local_files, delete_app_screenshots_files from api.utils.utils import delete_local_files, delete_app_screenshots_files
@ -133,19 +133,21 @@ class AppInfoView(APIView):
res = BaseResponse() res = BaseResponse()
if app_id: if app_id:
data = request.data data = request.data
if MigrateStorageState(request.user.uid).get_state():
res.code = 1008
res.msg = "数据迁移中,无法处理该操作"
return Response(res.dict)
clean = data.get("clean", None) clean = data.get("clean", None)
if clean: if clean:
if CleanAppSignDataState.get_state(request.user.uid): with CleanAppSignDataState(request.user.uid) as state:
res.code = 1008 if state:
res.msg = "数据清理中,请耐心等待" logger.info(f"app_id:{app_id} clean:{clean} ,close super_sign should clean_app_by_user_obj")
return Response(res.dict) app_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first()
logger.info(f"app_id:{app_id} clean:{clean} ,close super_sign should clean_app_by_user_obj") IosUtils.clean_app_by_user_obj(app_obj)
CleanAppSignDataState.set_state(request.user.uid, timeout=60 * 10) else:
app_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first() res.code = 1008
IosUtils.clean_app_by_user_obj(app_obj) res.msg = "数据清理中,请耐心等待"
CleanAppSignDataState.del_state(request.user.uid)
return Response(res.dict) return Response(res.dict)
has_combo = data.get("has_combo", None) has_combo = data.get("has_combo", None)
@ -285,6 +287,12 @@ class AppReleaseInfoView(APIView):
def delete(self, request, app_id, act): def delete(self, request, app_id, act):
res = BaseResponse() res = BaseResponse()
if app_id: if app_id:
if MigrateStorageState(request.user.uid).get_state():
res.code = 1008
res.msg = "数据迁移中,无法处理该操作"
return Response(res.dict)
app_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first() app_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first()
if app_obj: if app_obj:
storage = Storage(request.user) storage = Storage(request.user)
@ -338,6 +346,12 @@ class AppReleaseInfoView(APIView):
res = BaseResponse() res = BaseResponse()
res.data = {} res.data = {}
if app_id: if app_id:
if MigrateStorageState(request.user.uid).get_state():
res.code = 1008
res.msg = "数据迁移中,无法处理该操作"
return Response(res.dict)
app_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first() app_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first()
if app_obj: if app_obj:
app_release_objs = AppReleaseInfo.objects.filter(app_id=app_obj, release_id=act) app_release_objs = AppReleaseInfo.objects.filter(app_id=app_obj, release_id=act)

@ -9,8 +9,9 @@ import logging
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
from api.base_views import storage_change from api.base_views import storage_change, app_delete
from api.models import AppStorage, UserInfo from api.models import AppStorage, UserInfo, Apps
from api.utils.app.apputils import clean_history_apps
from api.utils.auth import ExpiringTokenAuthentication, StoragePermission from api.utils.auth import ExpiringTokenAuthentication, StoragePermission
from api.utils.response import BaseResponse from api.utils.response import BaseResponse
from api.utils.serializer import StorageSerializer from api.utils.serializer import StorageSerializer
@ -96,14 +97,15 @@ class StorageView(APIView):
use_storage_id = data.get("use_storage_id", None) use_storage_id = data.get("use_storage_id", None)
force = data.get("force", None) force = data.get("force", None)
if use_storage_id: if use_storage_id:
if MigrateStorageState.get_state(request.user.uid): with MigrateStorageState(request.user.uid) as state:
res.code = 1007 if state:
res.msg = "数据迁移中,请耐心等待" if not storage_change(use_storage_id, request.user, force):
return Response(res.dict) res.code = 1006
MigrateStorageState.set_state(request.user.uid) res.msg = '修改失败'
if not storage_change(use_storage_id, request.user, force): else:
res.code = 1006 res.code = 1007
res.msg = '修改失败' res.msg = "数据迁移中,请耐心等待"
return Response(res.dict) return Response(res.dict)
storage_id = data.get("id", None) storage_id = data.get("id", None)
@ -152,3 +154,29 @@ class StorageView(APIView):
res.code = 1004 res.code = 1004
res.msg = '该存储不存在' res.msg = '该存储不存在'
return Response(res.dict) return Response(res.dict)
class CleanStorageView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ]
permission_classes = [StoragePermission, ]
def post(self, request):
res = BaseResponse()
data = request.data
logger.info(f"user {request.user} clean storage data:{data}")
act = data.get('act', '')
if act in ['history', 'all']:
if request.user.check_password(data.get('confirm_pwd', '')):
app_obj_lists = Apps.objects.filter(user_id=request.user).all()
for app_obj in app_obj_lists:
if act == 'all':
res = app_delete(app_obj)
elif act == 'history':
clean_history_apps(app_obj, request.user, 1)
else:
res.code = 1007
res.msg = "密码有误,请检查"
else:
res.code = 1007
res.msg = "参数不合法,清理失败"
return Response(res.dict)

@ -128,17 +128,16 @@ class DeveloperView(APIView):
res.msg = result.get("err_info") res.msg = result.get("err_info")
return Response(res.dict) return Response(res.dict)
elif act == "cleandevice": elif act == "cleandevice":
if CleanSignDataState.get_state(request.user.uid): with CleanSignDataState(request.user.uid) as state:
res.code = 1008 if state:
res.msg = "数据清理中,请耐心等待" status, result = IosUtils.clean_developer(developer_obj, request.user, False)
return Response(res.dict) if not status:
CleanSignDataState.set_state(request.user.uid, timeout=60 * 10) res.code = 1008
status, result = IosUtils.clean_developer(developer_obj, request.user, False) res.msg = result.get("err_info")
CleanSignDataState.del_state(request.user.uid) else:
if not status: res.code = 1008
res.code = 1008 res.msg = "数据清理中,请耐心等待"
res.msg = result.get("err_info") return Response(res.dict)
return Response(res.dict)
elif act == 'disable': elif act == 'disable':
developer_obj.is_actived = False developer_obj.is_actived = False
developer_obj.save(update_fields=['is_actived']) developer_obj.save(update_fields=['is_actived'])

@ -18,7 +18,7 @@ from api.utils.auth import ExpiringTokenAuthentication
from api.utils.baseutils import make_app_uuid, make_from_user_uuid from api.utils.baseutils import make_app_uuid, make_from_user_uuid
from api.utils.modelutils import get_app_domain_name, get_redirect_server_domain, check_super_sign_permission from api.utils.modelutils import get_app_domain_name, get_redirect_server_domain, check_super_sign_permission
from api.utils.response import BaseResponse from api.utils.response import BaseResponse
from api.utils.storage.caches import upload_file_tmp_name, del_cache_response_by_short from api.utils.storage.caches import upload_file_tmp_name, del_cache_response_by_short, MigrateStorageState
from api.utils.storage.storage import Storage from api.utils.storage.storage import Storage
from fir_ser import settings from fir_ser import settings
@ -39,6 +39,11 @@ class AppAnalyseView(APIView):
bundle_id = request.data.get("bundleid", None) bundle_id = request.data.get("bundleid", None)
app_type = request.data.get("type", None) app_type = request.data.get("type", None)
if MigrateStorageState(request.user.uid).get_state():
res.code = 1008
res.msg = "数据迁移中,无法处理该操作"
return Response(res.dict)
if bundle_id and app_type: if bundle_id and app_type:
ap = 'apk' ap = 'apk'
if app_type.lower() == 'iOS'.lower(): if app_type.lower() == 'iOS'.lower():
@ -99,6 +104,12 @@ class AppAnalyseView(APIView):
:return: :return:
""" """
res = BaseResponse() res = BaseResponse()
if MigrateStorageState(request.user.uid).get_state():
res.code = 1008
res.msg = "数据迁移中,无法处理该操作"
return Response(res.dict)
data = request.data data = request.data
app_info = { app_info = {
"labelname": data.get("appname"), "labelname": data.get("appname"),
@ -129,7 +140,7 @@ class AppAnalyseView(APIView):
app_obj = Apps.objects.filter(bundle_id=data.get("bundleid"), user_id=request.user).first() app_obj = Apps.objects.filter(bundle_id=data.get("bundleid"), user_id=request.user).first()
if app_obj: if app_obj:
c_task = run_resign_task(app_obj.pk, False, False) c_task = run_resign_task(app_obj.pk, False, False)
logger.info(f"app {app_obj} run_resign_task msg:{c_task}") logger.info(f"app {app_obj} run_resign_task end msg:{c_task}")
else: else:
storage.delete_file(app_tmp_filename) storage.delete_file(app_tmp_filename)
storage.delete_file(png_tmp_filename) storage.delete_file(png_tmp_filename)
@ -212,6 +223,11 @@ class UploadView(APIView):
""" """
res = BaseResponse() res = BaseResponse()
if MigrateStorageState(request.user.uid).get_state():
res.code = 1008
res.msg = "数据迁移中,无法处理该操作"
return Response(res.dict)
# 获取多个file # 获取多个file
files = request.FILES.getlist('file', None) files = request.FILES.getlist('file', None)
cert_info = request.data.get('certinfo', None) cert_info = request.data.get('certinfo', None)
@ -299,6 +315,12 @@ class UploadView(APIView):
:return: :return:
""" """
res = BaseResponse() res = BaseResponse()
if MigrateStorageState(request.user.uid).get_state():
res.code = 1008
res.msg = "数据迁移中,无法处理该操作"
return Response(res.dict)
cert_info = request.data.get('certinfo', None) cert_info = request.data.get('certinfo', None)
if cert_info: if cert_info:
app_id = cert_info.get("app_id", None) app_id = cert_info.get("app_id", None)

@ -246,6 +246,12 @@ class SENDERCONF(object):
class IPACONF(object): class IPACONF(object):
APPLE_DEVELOPER_API_PROXY = {
# 代理的作用,主要是为了加快苹果api的访问,在国内会出现卡死,访问超时等问题,怀疑是被苹果服务器拦截了
# 'http': '47.243.172.202:17897',
# 'https': '47.243.172.202:17897'
}
APPLE_DEVELOPER_API_TIMEOUT = 180 # 访问苹果api超时时间,默认3分钟
MOBILE_CONFIG_SIGN_SSL = { MOBILE_CONFIG_SIGN_SSL = {
# 描述文件是否签名,默认是关闭状态;如果开启,并且ssl_key_path 和 ssl_pem_path 正常,则使用填写的ssl进行签名,否则默认不签名 # 描述文件是否签名,默认是关闭状态;如果开启,并且ssl_key_path 和 ssl_pem_path 正常,则使用填写的ssl进行签名,否则默认不签名
'open': True, 'open': True,

@ -261,6 +261,10 @@ SERVER_DOMAIN = BASECONF.SERVER_DOMAIN
MOBILE_CONFIG_SIGN_SSL = IPACONF.MOBILE_CONFIG_SIGN_SSL MOBILE_CONFIG_SIGN_SSL = IPACONF.MOBILE_CONFIG_SIGN_SSL
APPLE_DEVELOPER_API_PROXY = IPACONF.APPLE_DEVELOPER_API_PROXY
APPLE_DEVELOPER_API_TIMEOUT = IPACONF.APPLE_DEVELOPER_API_TIMEOUT
DEFAULT_MOBILEPROVISION = IPACONF.DEFAULT_MOBILEPROVISION DEFAULT_MOBILEPROVISION = IPACONF.DEFAULT_MOBILEPROVISION
# DEFAULT_MOBILEPROVISION = { # DEFAULT_MOBILEPROVISION = {
# # 默认描述文件路径或者下载路径,用户企业签名或者超级签名 跳转 [设置 - 通用 - 描述文件|设备管理] 页面 # # 默认描述文件路径或者下载路径,用户企业签名或者超级签名 跳转 [设置 - 通用 - 描述文件|设备管理] 页面
@ -305,7 +309,7 @@ LOGGING = {
}, },
'handlers': { 'handlers': {
'console': { 'console': {
'level': 'DEBUG', 'level': 'INFO',
'filters': ['require_debug_true'], # 只有在Django debug为True时才在屏幕打印日志 'filters': ['require_debug_true'], # 只有在Django debug为True时才在屏幕打印日志
'class': 'logging.StreamHandler', 'class': 'logging.StreamHandler',
'formatter': 'simple' 'formatter': 'simple'

Loading…
Cancel
Save