add new functions

super_signature
nineven 5 years ago
parent 870646daeb
commit 85a1982129
  1. 6
      fir_client/src/components/FirAppInfossecurity.vue
  2. 36
      fir_client/src/components/FirApps.vue
  3. 14
      fir_client/src/components/FirDownload.vue
  4. 139
      fir_client/src/components/FirSuperSignBase.vue
  5. 1
      fir_ser/api/admin.py
  6. 157
      fir_ser/api/migrations/0001_initial.py
  7. 19
      fir_ser/api/migrations/0002_auto_20200303_1940.py
  8. 26
      fir_ser/api/migrations/0002_auto_20200503_1120.py
  9. 28
      fir_ser/api/migrations/0003_apptodeveloper.py
  10. 27
      fir_ser/api/migrations/0003_auto_20200306_1734.py
  11. 27
      fir_ser/api/migrations/0004_auto_20200306_2331.py
  12. 22
      fir_ser/api/migrations/0005_auto_20200307_0800.py
  13. 22
      fir_ser/api/migrations/0006_auto_20200307_0810.py
  14. 18
      fir_ser/api/migrations/0007_appreleaseinfo_changelog.py
  15. 23
      fir_ser/api/migrations/0008_auto_20200307_1249.py
  16. 26
      fir_ser/api/migrations/0009_auto_20200309_1424.py
  17. 27
      fir_ser/api/migrations/0010_auto_20200309_1918.py
  18. 23
      fir_ser/api/migrations/0011_auto_20200310_1019.py
  19. 18
      fir_ser/api/migrations/0012_userinfo_head_img.py
  20. 44
      fir_ser/api/migrations/0013_auto_20200323_2020.py
  21. 19
      fir_ser/api/migrations/0014_userinfo_storage.py
  22. 28
      fir_ser/api/migrations/0015_auto_20200326_1454.py
  23. 35
      fir_ser/api/migrations/0016_auto_20200327_1121.py
  24. 28
      fir_ser/api/migrations/0017_auto_20200331_1543.py
  25. 28
      fir_ser/api/migrations/0018_auto_20200407_1134.py
  26. 18
      fir_ser/api/migrations/0019_auto_20200407_1135.py
  27. 21
      fir_ser/api/migrations/0020_auto_20200407_1157.py
  28. 28
      fir_ser/api/migrations/0021_auto_20200410_1141.py
  29. 18
      fir_ser/api/migrations/0022_apps_isshow.py
  30. 18
      fir_ser/api/migrations/0023_appreleaseinfo_udid.py
  31. 28
      fir_ser/api/migrations/0024_auto_20200413_1557.py
  32. 18
      fir_ser/api/migrations/0025_appstorage_updated_time.py
  33. 18
      fir_ser/api/migrations/0026_auto_20200414_1505.py
  34. 18
      fir_ser/api/migrations/0027_apps_issupersign.py
  35. 31
      fir_ser/api/migrations/0028_appudid.py
  36. 38
      fir_ser/api/migrations/0029_auto_20200416_0915.py
  37. 18
      fir_ser/api/migrations/0030_appudid_updated_time.py
  38. 18
      fir_ser/api/migrations/0031_appudid_is_signed.py
  39. 49
      fir_ser/api/migrations/0032_appiosdeveloperinfo_appsupersignusedinfo.py
  40. 23
      fir_ser/api/migrations/0033_auto_20200425_1601.py
  41. 18
      fir_ser/api/migrations/0034_appiosdeveloperinfo_certid.py
  42. 21
      fir_ser/api/models.py
  43. 24
      fir_ser/api/utils/app/iossignapi.py
  44. 15
      fir_ser/api/utils/app/shellcmds.py
  45. 212
      fir_ser/api/utils/app/supersignutils.py
  46. 53
      fir_ser/api/utils/crontab/runWin.py
  47. 4
      fir_ser/api/utils/serializer.py
  48. 30
      fir_ser/api/utils/storage/caches.py
  49. 25
      fir_ser/api/views/apps.py
  50. 13
      fir_ser/api/views/download.py
  51. 1
      fir_ser/api/views/login.py
  52. 63
      fir_ser/api/views/supersign.py
  53. 3
      fir_ser/fir_ser/urls.py
  54. 6
      fir_ser/requirements.txt
  55. 11
      fir_ser/supersign/scripts/apple_api.rb

@ -54,7 +54,7 @@
inactive-value="off">
</el-switch>
</el-tooltip>
<el-button @click="clean_app" v-if="currentapp.issupersign === 0 && currentapp.count !== 0" style="margin-left: 20px" size="small" type="info" plain>清理开发者账户脏数据</el-button>
</el-form-item>
@ -79,9 +79,13 @@
passwordflag:false,
showdownloadflag:false,
showsupersignflag:false,
clecount:0
}
},
methods: {
clean_app(){
this.saveappinfo({"clean":true})
},
saveappinfo(data) {
updateapp(data => {
if (data.code === 1000) {

@ -8,11 +8,15 @@
:title="getDelappTitle"
:visible.sync="willDeleteApp"
width="50%">
<span>删除后不可恢复请谨慎操作</span>
<span v-if="delapp.issupersign">请先在权限管理页面关闭超级签名</span>
<span v-else>删除后不可恢复请谨慎操作</span>
<span slot="footer" class="dialog-footer">
<el-button @click="willDeleteApp = false"> </el-button>
<el-button type="danger" @click="delApp"> </el-button>
</span>
<el-button v-if="delapp.issupersign" type="danger" @click="$router.push({name: 'FirAppInfossecurity', params: {id: delapp.app_id}})"> </el-button>
<el-button v-else type="danger" @click="delApp"> </el-button>
</span>
</el-dialog>
@ -337,18 +341,21 @@
</tr>
<tr v-if="r.type === 1 && r.master_release.binary_url === ''">
<td class="ng-binding">打包类型</td>
<td><span class="ng-binding">
{{ r.master_release.release_type|getiOStype }}
</span></td>
<td>
<span class="ng-binding">
{{ r.master_release.release_type|getiOStype }}
<span v-if="r.issupersign">超级签名</span>
</span>
</td>
</tr>
<tr v-if=" r.master_release.binary_url !== ''">
<td>第三方平台下载</td>
<td>
<span>
<el-tooltip :content="r.master_release.binary_url" placement="top">
<a target="_blank" :href="r.master_release.binary_url">{{ r.master_release.binary_url| autoformat}}</a>
</el-tooltip>
</span>
<span>
<el-tooltip :content="r.master_release.binary_url" placement="top">
<a target="_blank" :href="r.master_release.binary_url">{{ r.master_release.binary_url| autoformat}}</a>
</el-tooltip>
</span>
</td>
</tr>
@ -364,8 +371,10 @@
<i class="icon-eye el-icon-view"></i> 预览
</el-button>
<el-button v-if="r.issupersign" @click="DeleteApp(r)" class="btn btn-remove" icon="el-icon-loading"
circle></el-button>
<el-button @click="DeleteApp(r)" class="btn btn-remove" icon="el-icon-delete"
<el-button v-else @click="DeleteApp(r)" class="btn btn-remove" icon="el-icon-delete"
circle></el-button>
</div>
@ -739,7 +748,8 @@
return size / 1000;
},
autoformat: function (packname) {
if ((packname.length) > 20) {
if (packname && (packname.length) > 20) {
return packname.split('').slice(0, 20).join('') + '...';
} else {
return packname

@ -31,7 +31,8 @@
<span id="qrcode" class="qrcode">
</span>
</div>
<p class="scan-tips wrapper icon-warp" >{{ mcurrentappinfo.release_type|getiOStype }}</p>
<p v-if="currentappinfo.issupersign" class="scan-tips wrapper icon-warp" >超级签</p>
<p v-else class="scan-tips wrapper icon-warp" >{{ mcurrentappinfo.release_type|getiOStype }}</p>
<h1 class="name wrapper">
<span class="icon-warp" style="margin-left:0px">
<i v-if="currentappinfo.type === 0 && agent !== ''" class="iconfont icon-android2"/>
@ -175,7 +176,10 @@
this.isdownload = true;
getdownloadurl(res=>{
if(res.code === 1000){
if(res.data.download_url === ""){
window.location.href=this.full_url;
return
}
if(this.currentappinfo.type === 1){
if(this.currentappinfo.issupersign && this.udid !== this.$route.query.udid){
if(this.agent !== ''){
@ -209,7 +213,7 @@
'short': this.currentappinfo.short,
'release_id': this.mcurrentappinfo.release_id,
'password':this.password,
'udid':this.udid
'udid':this.udid,
},
'app_id': this.currentappinfo.app_id
})
@ -223,7 +227,7 @@
})
},
getDownloadTokenFun() {
let params={ "short": this.$route.params.short };
let params={ "short": this.$route.params.short ,"time":new Date().getTime()};
if(this.$route.query.release_id){
params["release_id"]=this.$route.query.release_id
}
@ -363,7 +367,7 @@
this.getAgent();
}, mounted() {
this.getDownloadTokenFun();
this.full_url = location.href;
this.full_url = location.href.split("?")[0];
this.qrcode();
},filters:{
getiOStype: function (type) {

@ -1,5 +1,48 @@
<template>
<el-main>
<el-dialog :title="title" :visible.sync="dialogaddDeveloperVisible" :destroy-on-close="true" :close-on-click-modal="false" style="text-align:center">
<el-form ref="storageinfoform" :model="editdeveloperinfo"
label-width="80px" style="margin:0 auto;">
<el-form-item label-width="110px" label="APP_ID">
<el-input :disabled='isedit' v-model="editdeveloperinfo.email" ></el-input>
</el-form-item>
<el-form-item label-width="110px" label="password">
<el-input v-model="editdeveloperinfo.password" :placeholder="placeholder"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="设备数量">
<el-input v-model="editdeveloperinfo.usable_number"></el-input>
</el-form-item>
<el-form-item label-width="110px" label="备注">
<el-input v-model="editdeveloperinfo.description"></el-input>
</el-form-item>
<div style="" >
<el-button @click="updateorcreate">保存</el-button>
<el-button @click="canceledit">取消</el-button>
</div>
</el-form>
</el-dialog>
<el-dialog
title="请输入验证码"
:visible.sync="codeactiveVisible"
width="30%"
center>
<span slot="footer" class="dialog-footer">
<el-button @click="codeactiveVisible = false"> </el-button>
<el-button type="primary" @click="codeactiveVisible = false"> </el-button>
</span>
</el-dialog>
<el-tabs v-model="activeName" type="border-card" @tab-click="handleClick" tab-position="top">
<el-tab-pane label="开发者账户" name="iosdeveloper">
<el-table
@ -17,10 +60,10 @@
<el-table-column
prop="is_actived"
label="是否激活"
width="100">
width="110">
<template slot-scope="scope" >
<el-button v-if="scope.row.is_actived === true" type="success" size="small">已激活</el-button>
<el-button v-else type="danger" size="small">未激活</el-button>
<el-button v-else type="danger" size="small" @click="activedeveloperFun(scope.row)">点击激活</el-button>
</template>
</el-table-column>
@ -55,7 +98,7 @@
<el-button
size="mini"
@click="handleEdit(scope.$index, scope.row)">编辑</el-button>
@click="handleEditDeveloper(scope.row)">编辑</el-button>
<el-button
size="mini"
type="danger"
@ -67,7 +110,7 @@
</el-tab-pane>
<el-tab-pane label="添加开发者">添加开发者</el-tab-pane>
<el-tab-pane label="添加开发者" name="adddeveloper">添加开发者</el-tab-pane>
<el-tab-pane label="设备消耗" name="useddevices">
<el-table
:data="app_devices_lists"
@ -203,10 +246,70 @@
app_udid_lists:[],
activeName:"iosdeveloper",
udidsearch:"",
Bundleidsearch:""
Bundleidsearch:"",
dialogaddDeveloperVisible:false,
title:"",
editdeveloperinfo:{},
isedit:false,
placeholder:"",
codeactiveVisible:false,
}
},
methods: {
IsNum(s){
if(s!=null){
var r,re;
re = /\d*/i; //\d,*
r = s.match(re);
return (r==s)?true:false;
}
return false;
},
inputcode(developer){
this.$prompt('请输入验证码', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
closeOnClickModal:false,
}).then(({ value }) => {
if(value.toString().length>5 && this.IsNum(value)){
this.iosdeveloperFun({"methods":"PUT","data":{"email":developer.email,"act":"nowactive","code":value}});
}
}).catch(() => {
this.$message({
type: 'info',
message: '取消激活'
});
});
},
activedeveloperFun(developer){
this.iosdeveloperFun({"methods":"PUT","data":{"email":developer.email,"act":"preactive"}});
this.inputcode(developer)
},
canceledit(){
this.dialogaddDeveloperVisible=false;
this.editdeveloperinfo={};
this.isedit=false;
this.placeholder=""
},
handleEditDeveloper(developer_info){
this.editdeveloperinfo=developer_info;
this.title='编辑开发者账户';
this.dialogaddDeveloperVisible=true;
this.isedit=true;
this.placeholder="为空表示不修改密码"
},
updateorcreate(){
if(this.isedit){
this.iosdeveloperFun({"methods":"PUT","data":this.editdeveloperinfo})
}else {
if(this.editdeveloperinfo.email && this.editdeveloperinfo.password && this.editdeveloperinfo.usable_number ){
this.iosdeveloperFun({"methods":"POST","data":this.editdeveloperinfo});
}else {
this.$message.warning("输入格式有误")
}
}
},
handleDelete(b){
// eslint-disable-next-line no-console
console.log(b)
@ -218,6 +321,9 @@
this.iosdevicesFun()
}else if(tab.name === "devicesudid"){
this.iosdevicesudidFun('GET')
}else if(tab.name === "adddeveloper"){
this.title='新增私有开发者账户';
this.dialogaddDeveloperVisible=true;
}
},
@ -250,18 +356,27 @@
"methods":"GET"
})
},
iosdeveloperFun(){
iosdeveloperFun(params){
iosdeveloper(data=>{
if(data.code === 1000){
this.app_developer_lists = data.data;
this.$store.dispatch("getUser",data.userinfo);
this.$store.dispatch('doucurrentapp', {});
// eslint-disable-next-line no-console
console.log(data)
if(this.dialogaddDeveloperVisible){
this.canceledit();
this.$message.success("操作成功");
this.activeName="iosdeveloper";
this.editdeveloperinfo={};
}
}
},{
"methods":"GET"
})
else if(data.code === 1008){
this.$message.error(data.msg);
}
else {
this.$message.error("操作失败")
}
},params)
},
iosdevicesudidFun(action,data){
iosdevicesudid(data=>{
@ -274,7 +389,7 @@
}
}, mounted() {
this.iosdeveloperFun()
this.iosdeveloperFun({"methods":"GET"})
}, watch: {
// eslint-disable-next-line no-unused-vars
udidsearch: function (val, oldVal) {

@ -13,4 +13,5 @@ admin.site.register(AppStorage)
admin.site.register(AppUDID)
admin.site.register(AppIOSDeveloperInfo)
admin.site.register(APPSuperSignUsedInfo)
admin.site.register(APPToDeveloper)

@ -1,4 +1,4 @@
# Generated by Django 3.0.3 on 2020-03-03 11:27
# Generated by Django 3.0.3 on 2020-05-01 16:40
from django.conf import settings
import django.contrib.auth.models
@ -19,6 +19,7 @@ class Migration(migrations.Migration):
name='UserInfo',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
@ -26,21 +27,22 @@ class Migration(migrations.Migration):
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('username', models.CharField(max_length=64, unique=True, verbose_name='用户名')),
('email', models.EmailField(blank=True, max_length=255, null=True, unique=True, verbose_name='email address')),
('uid', models.CharField(max_length=64, unique=True)),
('uid', models.CharField(db_index=True, max_length=64, unique=True)),
('mobile', models.BigIntegerField(help_text='用于手机验证码登录', null=True, unique=True, verbose_name='手机')),
('qq', models.CharField(blank=True, db_index=True, max_length=64, null=True, verbose_name='QQ')),
('is_active', models.BooleanField(default=True, verbose_name='账户状态')),
('qq', models.BigIntegerField(blank=True, db_index=True, null=True, verbose_name='QQ')),
('is_active', models.BooleanField(default=True, verbose_name='账户状态,默认启用')),
('job', models.TextField(blank=True, max_length=128, null=True, verbose_name='职位')),
('company', models.CharField(blank=True, max_length=128, null=True, verbose_name='公司')),
('gender', models.SmallIntegerField(choices=[(0, '保密'), (1, ''), (2, '')], default=0, verbose_name='性别')),
('password', models.CharField(help_text="<a class='btn-link' href='password'>重置密码</a>", max_length=128, verbose_name='password')),
('head_img', models.CharField(default='/static/frontend/head_portrait/logo@2x.png', max_length=256, verbose_name='个人头像')),
('head_img', models.CharField(default='head_img.jpeg', max_length=256, verbose_name='个人头像')),
('role', models.SmallIntegerField(choices=[(0, '普通会员'), (1, 'VIP'), (2, 'SVIP'), (3, '管理员')], default=0, verbose_name='角色')),
('memo', models.TextField(blank=True, default=None, null=True, verbose_name='备注')),
('date_joined', models.DateTimeField(auto_now_add=True, verbose_name='注册时间')),
('download_times', models.IntegerField(default=100, verbose_name='下载次数')),
('all_download_times', models.BigIntegerField(default=0, verbose_name='总共下载次数')),
('domain_name', models.CharField(blank=True, max_length=64, null=True, verbose_name='域名')),
('history_release_limit', models.IntegerField(blank=True, default=10, null=True, verbose_name='app 历史记录版本')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
],
options={
'verbose_name': '账户信息',
@ -50,6 +52,51 @@ class Migration(migrations.Migration):
('objects', django.contrib.auth.models.UserManager()),
],
),
migrations.CreateModel(
name='AppIOSDeveloperInfo',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=64, unique=True, verbose_name='开发者标识')),
('email', models.EmailField(blank=True, max_length=64, null=True, unique=True, verbose_name='email address')),
('password', models.CharField(max_length=64)),
('is_actived', models.BooleanField(default=False, verbose_name='是否已经激活')),
('certid', models.CharField(blank=True, max_length=64, null=True, verbose_name='超级签名自动创建证书ID')),
('usable_number', models.IntegerField(default=100, verbose_name='可使用设备数')),
('use_number', models.IntegerField(default=0, verbose_name='已消耗设备数')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('description', models.TextField(blank=True, default='', null=True, verbose_name='备注')),
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')),
],
options={
'verbose_name': '苹果开发者账户',
'verbose_name_plural': '苹果开发者账户',
},
),
migrations.CreateModel(
name='Apps',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('app_id', models.CharField(db_index=True, max_length=64, unique=True)),
('type', models.SmallIntegerField(choices=[(0, 'android'), (1, 'ios')], default=0, verbose_name='类型')),
('name', models.CharField(blank=True, max_length=32, null=True, verbose_name='应用名称')),
('short', models.CharField(db_index=True, max_length=16, unique=True, verbose_name='短链接')),
('bundle_id', models.CharField(blank=True, max_length=64, verbose_name='bundle id')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('count_hits', models.BigIntegerField(default=0, verbose_name='下载次数')),
('password', models.CharField(default='', help_text='默认 没有密码', max_length=32, verbose_name='访问密码')),
('isshow', models.BigIntegerField(default=1, verbose_name='下载页可见')),
('issupersign', models.BigIntegerField(default=False, verbose_name='是否超级签名包')),
('description', models.TextField(blank=True, default=None, null=True, verbose_name='描述')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('has_combo', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='combo_app_info', to='api.Apps', verbose_name='关联应用')),
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')),
],
options={
'verbose_name': '应用信息',
'verbose_name_plural': '应用信息',
},
),
migrations.CreateModel(
name='VerifyName',
fields=[
@ -70,50 +117,110 @@ class Migration(migrations.Migration):
name='Token',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('access_token', models.CharField(max_length=42, unique=True)),
('access_token', models.CharField(max_length=64, unique=True)),
('created', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='auth_token', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='auth_token', to=settings.AUTH_USER_MODEL, verbose_name='关联用户')),
],
),
migrations.CreateModel(
name='Apps',
name='AppUDID',
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唯一标识')),
('product', models.CharField(blank=True, max_length=64, null=True, verbose_name='产品')),
('serial', models.CharField(blank=True, max_length=64, null=True, verbose_name='序列号')),
('version', models.CharField(blank=True, max_length=64, null=True, verbose_name='型号')),
('imei', models.CharField(blank=True, max_length=64, null=True, verbose_name='型号')),
('iccid', models.CharField(blank=True, max_length=64, null=True, verbose_name='型号')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('is_signed', models.BooleanField(default=False, verbose_name='是否完成签名打包')),
('binary_file', models.CharField(blank=True, max_length=128, null=True, verbose_name='签名包名称')),
('app_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')),
],
options={
'verbose_name': '设备详情',
'verbose_name_plural': '设备详情',
'unique_together': {('app_id', 'udid')},
},
),
migrations.CreateModel(
name='APPSuperSignUsedInfo',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('app_id', models.CharField(max_length=64, unique=True)),
('type', models.SmallIntegerField(choices=[(0, 'ios'), (1, 'android')], default=0, verbose_name='类型')),
('name', models.CharField(blank=True, max_length=32, null=True, verbose_name='应用名称')),
('short', models.CharField(max_length=16, unique=True, verbose_name='短链接')),
('bundle_id', models.CharField(blank=True, max_length=64, verbose_name='bundle id')),
('icon_url', models.CharField(blank=True, max_length=128, verbose_name='图标url')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('count_hits', models.BigIntegerField(verbose_name='下载次数')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('has_combo', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='combo_app_info', to='api.Apps', verbose_name='关联应用')),
('app_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')),
('developerid', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.AppIOSDeveloperInfo', verbose_name='所使用苹果开发者账户')),
('udid', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.AppUDID', verbose_name='所消耗的udid')),
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')),
],
options={
'verbose_name': '应用信息',
'verbose_name_plural': '应用信息',
'verbose_name': '设备使用统计',
'verbose_name_plural': '设备使用统计',
},
),
migrations.CreateModel(
name='AppStorage',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(blank=True, max_length=64, null=True, verbose_name='存储名字')),
('storage_type', models.SmallIntegerField(choices=[(0, '本地存储'), (1, '七牛云存储'), (2, '阿里云存储'), (3, '默认存储')], default=3, verbose_name='存储类型')),
('access_key', models.CharField(blank=True, max_length=128, null=True, verbose_name='存储访问key')),
('secret_key', models.CharField(blank=True, max_length=128, null=True, verbose_name='存储访问secret')),
('bucket_name', models.CharField(blank=True, max_length=128, null=True, verbose_name='存储空间bucket_name')),
('domain_name', models.CharField(blank=True, help_text='fly-storage.dvcloud.xin,可以自定义端口', max_length=128, null=True, verbose_name='下载域名')),
('is_https', models.BooleanField(default=True, verbose_name='是否支持https')),
('additionalparameters', models.TextField(blank=True, default=None, help_text='阿里云:{"sts_role_arn":"arn信息","endpoint":""} ', null=True, verbose_name='额外参数')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('description', models.TextField(blank=True, default='', null=True, verbose_name='备注')),
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')),
],
options={
'verbose_name': '存储配置',
'verbose_name_plural': '存储配置',
},
),
migrations.CreateModel(
name='AppReleaseInfo',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('is_master', models.BooleanField(default=True, verbose_name='是否事master版本')),
('release_id', models.CharField(max_length=64, unique=True, verbose_name='release 版本id')),
('is_master', models.BooleanField(default=True, verbose_name='是否master版本')),
('release_id', models.CharField(db_index=True, max_length=64, unique=True, verbose_name='release 版本id')),
('build_version', models.CharField(blank=True, max_length=16, verbose_name='build版本')),
('app_version', models.CharField(blank=True, max_length=16, verbose_name='app版本')),
('release_type', models.SmallIntegerField(choices=[(0, 'android'), (1, 'adhoc'), (2, '')], default=0, verbose_name='版本类型')),
('release_type', models.SmallIntegerField(choices=[(0, 'android'), (1, 'adhoc'), (2, 'Inhouse'), (3, 'unknown')], default=0, verbose_name='版本类型')),
('minimum_os_version', models.CharField(max_length=64, verbose_name='应用可安装的最低系统版本')),
('binary_size', models.BigIntegerField(verbose_name='应用大小')),
('binary_url', models.CharField(blank=True, max_length=128, verbose_name='APPurl')),
('binary_url', models.CharField(blank=True, max_length=128, verbose_name='第三方下载URL')),
('icon_url', models.CharField(blank=True, max_length=128, verbose_name='图标url')),
('changelog', models.TextField(blank=True, default=None, null=True, verbose_name='更新日志')),
('udid', models.TextField(blank=True, default='', null=True, verbose_name='ios内测版 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='关联APP')),
('app_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')),
],
options={
'verbose_name': '应用详情',
'verbose_name_plural': '应用详情',
},
),
migrations.AddField(
model_name='userinfo',
name='storage',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='app_storage', to='api.AppStorage', verbose_name='存储'),
),
migrations.AddField(
model_name='userinfo',
name='user_permissions',
field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions'),
),
migrations.AddIndex(
model_name='apps',
index=models.Index(fields=['app_id'], name='api_apps_app_id_4c0254_idx'),
),
migrations.AddIndex(
model_name='apps',
index=models.Index(fields=['id', 'user_id', 'type'], name='api_apps_id_226a6b_idx'),
),
]

@ -1,19 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-03 11:40
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('api', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='apps',
name='has_combo',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='combo_app_info', to='api.Apps', verbose_name='关联应用'),
),
]

@ -0,0 +1,26 @@
# Generated by Django 3.0.3 on 2020-05-03 11:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='appiosdeveloperinfo',
name='email',
field=models.EmailField(blank=True, max_length=64, null=True, verbose_name='email address'),
),
migrations.AlterUniqueTogether(
name='appiosdeveloperinfo',
unique_together={('user_id', 'email')},
),
migrations.RemoveField(
model_name='appiosdeveloperinfo',
name='name',
),
]

@ -0,0 +1,28 @@
# Generated by Django 3.0.3 on 2020-05-03 21:16
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('api', '0002_auto_20200503_1120'),
]
operations = [
migrations.CreateModel(
name='APPToDeveloper',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('binary_file', models.CharField(blank=True, max_length=128, null=True, verbose_name='签名包名称')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('app_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')),
('developerid', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.AppIOSDeveloperInfo', verbose_name='所使用苹果开发者账户')),
],
options={
'verbose_name': '设备使用统计',
'verbose_name_plural': '设备使用统计',
},
),
]

@ -1,27 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-06 09:34
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('api', '0002_auto_20200303_1940'),
]
operations = [
migrations.AlterField(
model_name='appreleaseinfo',
name='app_id',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP'),
),
migrations.CreateModel(
name='AppStorage',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('app_file', models.FileField(upload_to='')),
('name', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='api.AppReleaseInfo')),
],
),
]

@ -1,27 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-06 15:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0003_auto_20200306_1734'),
]
operations = [
migrations.RemoveField(
model_name='apps',
name='icon_url',
),
migrations.AddField(
model_name='appreleaseinfo',
name='icon_url',
field=models.CharField(blank=True, max_length=128, verbose_name='图标url'),
),
migrations.AlterField(
model_name='appreleaseinfo',
name='release_type',
field=models.SmallIntegerField(choices=[(0, 'android'), (1, 'adhoc'), (2, 'Inhouse'), (3, 'unknown')], default=0, verbose_name='版本类型'),
),
]

@ -1,22 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-07 00:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0004_auto_20200306_2331'),
]
operations = [
migrations.RemoveField(
model_name='apps',
name='name',
),
migrations.AddField(
model_name='appreleaseinfo',
name='name',
field=models.CharField(blank=True, max_length=32, null=True, verbose_name='应用名称'),
),
]

@ -1,22 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-07 00:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0005_auto_20200307_0800'),
]
operations = [
migrations.RemoveField(
model_name='appreleaseinfo',
name='name',
),
migrations.AddField(
model_name='apps',
name='name',
field=models.CharField(blank=True, max_length=32, null=True, verbose_name='应用名称'),
),
]

@ -1,18 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-07 01:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0006_auto_20200307_0810'),
]
operations = [
migrations.AddField(
model_name='appreleaseinfo',
name='changelog',
field=models.TextField(blank=True, default=None, null=True, verbose_name='更新日志'),
),
]

@ -1,23 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-07 04:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0007_appreleaseinfo_changelog'),
]
operations = [
migrations.AddField(
model_name='apps',
name='description',
field=models.TextField(blank=True, default=None, null=True, verbose_name='描述'),
),
migrations.AlterField(
model_name='apps',
name='type',
field=models.SmallIntegerField(choices=[(0, 'android'), (1, 'ios')], default=0, verbose_name='类型'),
),
]

@ -1,26 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-09 06:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0008_auto_20200307_1249'),
]
operations = [
migrations.AddField(
model_name='userinfo',
name='domain_name',
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='域名'),
),
migrations.AlterField(
model_name='apps',
name='count_hits',
field=models.BigIntegerField(default=0, verbose_name='下载次数'),
),
migrations.DeleteModel(
name='AppStorage',
),
]

@ -1,27 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-09 11:18
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0009_auto_20200309_1424'),
]
operations = [
migrations.RemoveField(
model_name='userinfo',
name='head_img',
),
migrations.AlterField(
model_name='userinfo',
name='password',
field=models.CharField(max_length=128, verbose_name='password'),
),
migrations.AlterField(
model_name='userinfo',
name='qq',
field=models.BigIntegerField(blank=True, db_index=True, max_length=64, null=True, verbose_name='QQ'),
),
]

@ -1,23 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-10 02:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0010_auto_20200309_1918'),
]
operations = [
migrations.AddField(
model_name='userinfo',
name='all_download_times',
field=models.IntegerField(default=0, verbose_name='总共下载次数'),
),
migrations.AlterField(
model_name='userinfo',
name='qq',
field=models.BigIntegerField(blank=True, db_index=True, null=True, verbose_name='QQ'),
),
]

@ -1,18 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-14 07:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0011_auto_20200310_1019'),
]
operations = [
migrations.AddField(
model_name='userinfo',
name='head_img',
field=models.CharField(default='/static/frontend/head_portrait/logo@2x.png', max_length=256, verbose_name='个人头像'),
),
]

@ -1,44 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-23 12:20
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('api', '0012_userinfo_head_img'),
]
operations = [
migrations.AlterField(
model_name='appreleaseinfo',
name='is_master',
field=models.BooleanField(default=True, verbose_name='是否master版本'),
),
migrations.AlterField(
model_name='userinfo',
name='head_img',
field=models.CharField(default='/files/imgs/head_img.jpeg', max_length=256, verbose_name='个人头像'),
),
migrations.CreateModel(
name='AppStorage',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(blank=True, max_length=64, null=True, verbose_name='存储名字')),
('storage_type', models.SmallIntegerField(choices=[(0, '本地存储'), (1, '七牛云存储'), (2, '阿里云存储'), (3, '默认存储')], default=3, verbose_name='存储类型')),
('access_key', models.CharField(blank=True, max_length=128, null=True, verbose_name='存储访问key')),
('secret_key', models.CharField(blank=True, max_length=128, null=True, verbose_name='存储访问secret')),
('bucket_name', models.CharField(blank=True, max_length=128, null=True, verbose_name='存储空间bucket_name')),
('additionalparameters', models.TextField(blank=True, help_text='阿里云:{"sts_role_arn":"arn信息","endpoint":""} 七牛云:{"domain_name":""}', max_length=256, null=True, verbose_name='额外参数')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('description', models.TextField(blank=True, default=None, null=True, verbose_name='备注')),
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')),
],
options={
'verbose_name': '存储配置',
'verbose_name_plural': '存储配置',
},
),
]

@ -1,19 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-23 12:35
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('api', '0013_auto_20200323_2020'),
]
operations = [
migrations.AddField(
model_name='userinfo',
name='storage',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='app_storage', to='api.AppStorage', verbose_name='存储'),
),
]

@ -1,28 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-26 06:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0014_userinfo_storage'),
]
operations = [
migrations.AddField(
model_name='userinfo',
name='history_release_limit',
field=models.IntegerField(blank=True, default=10, null=True, verbose_name='app 历史记录版本'),
),
migrations.AlterField(
model_name='userinfo',
name='all_download_times',
field=models.BigIntegerField(default=0, verbose_name='总共下载次数'),
),
migrations.AlterField(
model_name='userinfo',
name='head_img',
field=models.CharField(default='head_img.jpeg', max_length=256, verbose_name='个人头像'),
),
]

@ -1,35 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-27 03:21
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('api', '0015_auto_20200326_1454'),
]
operations = [
migrations.AlterField(
model_name='appstorage',
name='additionalparameters',
field=models.TextField(blank=True, help_text='阿里云:{"sts_role_arn":"arn信息","endpoint":""} 七牛云:{"domain_name":""} 本地存储:{"domain_name":""}', max_length=256, null=True, verbose_name='额外参数'),
),
migrations.AlterField(
model_name='token',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='auth_token', to=settings.AUTH_USER_MODEL, verbose_name='关联用户'),
),
migrations.AlterField(
model_name='userinfo',
name='is_active',
field=models.BooleanField(default=True, verbose_name='账户状态,默认启用'),
),
migrations.AlterField(
model_name='userinfo',
name='storage',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='app_storage', to='api.AppStorage', verbose_name='存储'),
),
]

@ -1,28 +0,0 @@
# Generated by Django 3.0.3 on 2020-03-31 07:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0016_auto_20200327_1121'),
]
operations = [
migrations.AddField(
model_name='appstorage',
name='domain_name',
field=models.CharField(blank=True, help_text='fly-storage.dvcloud.xin,可以自定义端口', max_length=128, null=True, verbose_name='下载域名'),
),
migrations.AddField(
model_name='appstorage',
name='is_https',
field=models.BooleanField(blank=True, default=True, null=True, verbose_name='是否支持https'),
),
migrations.AlterField(
model_name='appstorage',
name='additionalparameters',
field=models.TextField(blank=True, help_text='阿里云:{"sts_role_arn":"arn信息","endpoint":""} ', max_length=256, null=True, verbose_name='额外参数'),
),
]

@ -1,28 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-07 03:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0017_auto_20200331_1543'),
]
operations = [
migrations.AlterField(
model_name='appreleaseinfo',
name='release_id',
field=models.CharField(db_index=True, max_length=64, unique=True, verbose_name='release 版本id'),
),
migrations.AlterField(
model_name='apps',
name='app_id',
field=models.CharField(db_index=True, max_length=64, unique=True),
),
migrations.AlterField(
model_name='apps',
name='short',
field=models.CharField(db_index=True, max_length=16, unique=True, verbose_name='短链接'),
),
]

@ -1,18 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-07 03:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0018_auto_20200407_1134'),
]
operations = [
migrations.AlterField(
model_name='userinfo',
name='uid',
field=models.CharField(db_index=True, max_length=64, unique=True),
),
]

@ -1,21 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-07 03:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0019_auto_20200407_1135'),
]
operations = [
migrations.AddIndex(
model_name='apps',
index=models.Index(fields=['app_id'], name='api_apps_app_id_4c0254_idx'),
),
migrations.AddIndex(
model_name='apps',
index=models.Index(fields=['id', 'user_id', 'type'], name='api_apps_id_226a6b_idx'),
),
]

@ -1,28 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-10 11:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0020_auto_20200407_1157'),
]
operations = [
migrations.AddField(
model_name='apps',
name='password',
field=models.CharField(default='', help_text='默认 没有密码', max_length=32, verbose_name='访问密码'),
),
migrations.AlterField(
model_name='appreleaseinfo',
name='binary_url',
field=models.CharField(blank=True, max_length=128, verbose_name='第三方下载URL'),
),
migrations.AlterField(
model_name='token',
name='access_token',
field=models.CharField(max_length=64, unique=True),
),
]

@ -1,18 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-10 17:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0021_auto_20200410_1141'),
]
operations = [
migrations.AddField(
model_name='apps',
name='isshow',
field=models.BigIntegerField(default=1, verbose_name='下载页可见'),
),
]

@ -1,18 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-11 10:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0022_apps_isshow'),
]
operations = [
migrations.AddField(
model_name='appreleaseinfo',
name='udid',
field=models.TextField(blank=True, default=None, null=True, verbose_name='ios内测版 udid'),
),
]

@ -1,28 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-13 15:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0023_appreleaseinfo_udid'),
]
operations = [
migrations.AlterField(
model_name='appreleaseinfo',
name='udid',
field=models.TextField(blank=True, default='', null=True, verbose_name='ios内测版 udid'),
),
migrations.AlterField(
model_name='appstorage',
name='additionalparameters',
field=models.TextField(blank=True, default=None, help_text='阿里云:{"sts_role_arn":"arn信息","endpoint":""} ', null=True, verbose_name='额外参数'),
),
migrations.AlterField(
model_name='appstorage',
name='is_https',
field=models.BooleanField(default=True, verbose_name='是否支持https'),
),
]

@ -1,18 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-14 10:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0024_auto_20200413_1557'),
]
operations = [
migrations.AddField(
model_name='appstorage',
name='updated_time',
field=models.DateTimeField(auto_now=True, verbose_name='更新时间'),
),
]

@ -1,18 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-14 15:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0025_appstorage_updated_time'),
]
operations = [
migrations.AlterField(
model_name='appstorage',
name='description',
field=models.TextField(blank=True, default='', null=True, verbose_name='备注'),
),
]

@ -1,18 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-15 19:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0026_auto_20200414_1505'),
]
operations = [
migrations.AddField(
model_name='apps',
name='issupersign',
field=models.BigIntegerField(default=False, verbose_name='是否超级签名包'),
),
]

@ -1,31 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-16 08:33
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('api', '0027_apps_issupersign'),
]
operations = [
migrations.CreateModel(
name='AppUDID',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('udid', models.CharField(db_index=True, max_length=64, unique=True, verbose_name='udid唯一标识')),
('product', models.CharField(db_index=True, max_length=64, verbose_name='产品')),
('serial', models.CharField(db_index=True, max_length=64, verbose_name='序列号')),
('version', models.CharField(db_index=True, max_length=64, verbose_name='型号')),
('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='属于哪个APP')),
],
options={
'verbose_name': '应用详情',
'verbose_name_plural': '应用详情',
'unique_together': {('app_id', 'udid')},
},
),
]

@ -1,38 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-16 09:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0028_appudid'),
]
operations = [
migrations.AddField(
model_name='appudid',
name='iccid',
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='型号'),
),
migrations.AddField(
model_name='appudid',
name='imei',
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='型号'),
),
migrations.AlterField(
model_name='appudid',
name='product',
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='产品'),
),
migrations.AlterField(
model_name='appudid',
name='serial',
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='序列号'),
),
migrations.AlterField(
model_name='appudid',
name='version',
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='型号'),
),
]

@ -1,18 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-16 10:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0029_auto_20200416_0915'),
]
operations = [
migrations.AddField(
model_name='appudid',
name='updated_time',
field=models.DateTimeField(auto_now=True, verbose_name='更新时间'),
),
]

@ -1,18 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-23 17:29
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0030_appudid_updated_time'),
]
operations = [
migrations.AddField(
model_name='appudid',
name='is_signed',
field=models.BooleanField(default=False, verbose_name='是否完成签名打包'),
),
]

@ -1,49 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-25 15:30
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('api', '0031_appudid_is_signed'),
]
operations = [
migrations.CreateModel(
name='APPSuperSignUsedInfo',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('app_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Apps', verbose_name='属于哪个APP')),
('udid', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.AppUDID', verbose_name='所消耗的udid')),
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')),
],
options={
'verbose_name': '设备使用统计',
'verbose_name_plural': '设备使用统计',
},
),
migrations.CreateModel(
name='AppIOSDeveloperInfo',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=64, unique=True, verbose_name='存储名字')),
('email', models.EmailField(blank=True, max_length=64, null=True, unique=True, verbose_name='email address')),
('password', models.CharField(max_length=64)),
('is_actived', models.BooleanField(default=False, verbose_name='是否已经激活')),
('usable_number', models.IntegerField(default=100, verbose_name='可使用设备数')),
('use_number', models.IntegerField(default=0, verbose_name='已消耗设备数')),
('created_time', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
('updated_time', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
('user_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='用户ID')),
],
options={
'verbose_name': '苹果开发者账户',
'verbose_name_plural': '苹果开发者账户',
},
),
]

@ -1,23 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-25 16:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0032_appiosdeveloperinfo_appsupersignusedinfo'),
]
operations = [
migrations.AddField(
model_name='appudid',
name='binary_file',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='签名包名称'),
),
migrations.AlterField(
model_name='appiosdeveloperinfo',
name='name',
field=models.CharField(max_length=64, unique=True, verbose_name='开发者标识'),
),
]

@ -1,18 +0,0 @@
# Generated by Django 3.0.3 on 2020-04-25 16:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0033_auto_20200425_1601'),
]
operations = [
migrations.AddField(
model_name='appiosdeveloperinfo',
name='certid',
field=models.CharField(blank=True, max_length=64, null=True, verbose_name='超级签名自动创建证书ID'),
),
]

@ -190,11 +190,9 @@ class AppUDID(models.Model):
class AppIOSDeveloperInfo(models.Model):
user_id = models.ForeignKey(to="UserInfo",verbose_name="用户ID",on_delete=models.CASCADE)
name = models.CharField(max_length=64,verbose_name="开发者标识",unique=True)
email = models.EmailField(
verbose_name='email address',
max_length=64,
unique=True,
blank=True,
null=True
)
@ -210,10 +208,12 @@ class AppIOSDeveloperInfo(models.Model):
class Meta:
verbose_name = '苹果开发者账户'
verbose_name_plural = "苹果开发者账户"
unique_together = ('user_id', 'email',)
def __str__(self):
return "%s-%s" % (self.name,self.email)
return "%s-%s" % (self.user_id,self.email)
class APPSuperSignUsedInfo(models.Model):
user_id = models.ForeignKey(to="UserInfo",verbose_name="用户ID",on_delete=models.CASCADE)
@ -227,4 +227,17 @@ class APPSuperSignUsedInfo(models.Model):
verbose_name_plural = "设备使用统计"
def __str__(self):
return "%s-%s-%s" % (self.user_id,self.app_id,self.udid)
return "%s-%s-%s" % (self.user_id,self.app_id,self.udid)
class APPToDeveloper(models.Model):
app_id = models.ForeignKey(to="Apps", on_delete=models.CASCADE, verbose_name="属于哪个APP")
developerid = models.ForeignKey(to="AppIOSDeveloperInfo",on_delete=models.CASCADE, verbose_name="所使用苹果开发者账户")
binary_file = models.CharField(max_length=128,blank=True,verbose_name="签名包名称",null=True)
updated_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
class Meta:
verbose_name = '应用开发者绑定'
verbose_name_plural = "应用开发者绑定"
def __str__(self):
return "%s-%s-%s" % (self.developerid,self.app_id,self.binary_file)

@ -9,7 +9,7 @@ from fir_ser.settings import SUPER_SIGN_ROOT
import os
from api.utils.app.randomstrings import make_app_uuid
def exec_shell(cmd,remote=False):
def exec_shell(cmd,remote=False,timeout=None):
if remote:
hostip="10.66.6.66"
port=65534
@ -20,10 +20,10 @@ def exec_shell(cmd,remote=False):
return result
else:
print(cmd)
result = shell_command(cmd)
result = shell_command(cmd,timeout)
print(result)
if result.get("exit_code") != 0 :
raise
return False
return result
@ -36,6 +36,20 @@ class AppDeveloperApi(object):
script_path=os.path.join(SUPER_SIGN_ROOT,'scripts','apple_api.rb')
self.cmd = "ruby %s '%s' '%s'" %(script_path,self.username,self.password)
def active(self,code):
timeout=10
self.cmd = self.cmd + " active "
if code:
self.cmd = "echo %s | %s" %(code,self.cmd)
timeout=None
try:
result = exec_shell(self.cmd,timeout=timeout)
if result["exit_code"] == 0:
return True
except Exception as e:
print(e)
return False
def create_cert(self,user_obj):
cert_dir_name = make_app_uuid(user_obj,self.username)
cert_dir_path = os.path.join(SUPER_SIGN_ROOT,cert_dir_name)
@ -68,8 +82,8 @@ class AppDeveloperApi(object):
self.cmd=self.cmd + " app add '%s' '%s'" %(bundleId,app_id)
result = exec_shell(self.cmd)
def del_app(self,bundleId):
self.cmd=self.cmd + " app del '%s' " %(bundleId)
def del_app(self,bundleId,app_id):
self.cmd=self.cmd + " app del '%s' '%s'" %(bundleId,app_id)
result = exec_shell(self.cmd)
# appdev = AppDeveloperApi("hehehuyu521@163.com","Hehehuyu123")

@ -3,8 +3,7 @@
# project: 3月
# author: liuyu
# date: 2020/3/6
import time,re,os
import time,re,os,signal
from subprocess import Popen, PIPE
import logging
import paramiko,json
@ -86,13 +85,23 @@ class SSHConnection(object):
if self._client:
self._client.close()
def shell_command(cmdstrs):
def shell_command(cmdstrs,timeout):
# cmdresult = re.split(r'\s+', cmdstrs)
# print(cmdresult)
result = default_result()
result['return_info'] = ''
shell_start_time = time.time()
child = Popen(cmdstrs, shell=True, stdout=PIPE, stderr=PIPE)
if timeout:
while child.poll() is None:
time.sleep(0.2)
now = time.time()
if int(now - shell_start_time) > timeout:
os.kill(child.pid, signal.SIGKILL)
os.waitpid(-1, os.WNOHANG)
result['exit_code']=126
return result
out, err = child.communicate()
shell_end_time = time.time()
result['shell_run_time'] = shell_end_time - shell_start_time

@ -7,9 +7,11 @@
import uuid, xmltodict, os, re
from fir_ser.settings import SUPER_SIGN_ROOT, MEDIA_ROOT, SERVER_DOMAIN
from api.utils.app.iossignapi import AppDeveloperApi, ResignApp
from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo
from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo,Apps,APPToDeveloper
from api.utils.app.randomstrings import make_app_uuid, make_from_user_uuid
from django.db.models import F
from api.utils.storage.storage import Storage
from api.utils.storage.caches import del_cache_response_by_short
def udid_bytes_to_dict(xml_stream):
@ -123,7 +125,7 @@ class IosUtils(object):
def get_developer_user_by_app_udid(self):
usedeviceobj = APPSuperSignUsedInfo.objects.filter(udid__udid=self.udid_info.get('udid'), app_id=self.app_obj,
user_id=self.user_obj).first()
if usedeviceobj and usedeviceobj.developer_obj.use_number < usedeviceobj.developer_obj.usable_number:
if usedeviceobj and usedeviceobj.developerid.use_number < usedeviceobj.developerid.usable_number:
developer_obj = usedeviceobj.developerid
else:
developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=self.user_obj, is_actived=True,
@ -134,7 +136,7 @@ class IosUtils(object):
def create_cert(self):
app_api_obj = AppDeveloperApi(**self.auth)
app_api_obj.create_cert(self.user_obj)
file_format_path_name = self.file_format_path()
file_format_path_name = file_format_path(self.user_obj,self.auth)
cert_info = None
try:
with open(file_format_path_name + '.info', "r") as f:
@ -142,9 +144,10 @@ class IosUtils(object):
except Exception as e:
print(e)
cert_id = re.findall(r'.*\n\tid=(.*),.*', cert_info)[0].replace('"', '')
AppIOSDeveloperInfo.objects.filter(user_id=self.user_obj, email=self.auth.get("username")).first().update(
is_actived=True, certid=cert_id)
developer_obj=AppIOSDeveloperInfo.objects.filter(user_id=self.user_obj, email=self.auth.get("username")).first()
developer_obj.is_actived=True
developer_obj.certid=cert_id
developer_obj.save()
def download_profile(self):
app_api_obj = AppDeveloperApi(**self.auth)
bundleId = self.app_obj.bundle_id
@ -153,13 +156,13 @@ class IosUtils(object):
device_name = self.udid_info.get('product')
app_api_obj.get_profile(bundleId, app_id, device_udid, device_name, self.get_profile_full_path())
def file_format_path(self):
cert_dir_name = make_app_uuid(self.app_obj.user_id, self.auth.get("username"))
cert_dir_path = os.path.join(SUPER_SIGN_ROOT, cert_dir_name)
if not os.path.isdir(cert_dir_path):
os.makedirs(cert_dir_path)
file_format_path_name = os.path.join(cert_dir_path, cert_dir_name)
return file_format_path_name
# def file_format_path(self):
# cert_dir_name = make_app_uuid(self.app_obj.user_id, self.auth.get("username"))
# cert_dir_path = os.path.join(SUPER_SIGN_ROOT, cert_dir_name)
# if not os.path.isdir(cert_dir_path):
# os.makedirs(cert_dir_path)
# file_format_path_name = os.path.join(cert_dir_path, cert_dir_name)
# return file_format_path_name
def get_profile_full_path(self):
cert_dir_name = make_app_uuid(self.user_obj, self.auth.get("username"))
@ -171,10 +174,11 @@ class IosUtils(object):
def resign(self):
if AppUDID.objects.filter(app_id=self.app_obj, udid=self.udid_info.get('udid')).first().is_signed:
return
if APPToDeveloper.objects.filter(app_id=self.app_obj).first():
return
self.download_profile()
file_format_path_name = self.file_format_path()
file_format_path_name = file_format_path(self.user_obj,self.auth)
my_local_key = file_format_path_name + ".key"
app_dev_pem = file_format_path_name + ".pem"
ResignAppObj = ResignApp(my_local_key, app_dev_pem)
@ -191,15 +195,36 @@ class IosUtils(object):
"is_signed": True,
"binary_file": random_file_name
}
#更新已经完成签名状态,设备消耗记录,和开发者已消耗数量
AppUDID.objects.filter(app_id=self.app_obj, udid=self.udid_info.get('udid')).update(**newdata)
APPSuperSignUsedInfo.objects.create(app_id=self.app_obj, user_id=self.user_obj, developerid=self.developer_obj,
udid=AppUDID.objects.filter(app_id=self.app_obj,udid=self.udid_info.get('udid')).first())
AppIOSDeveloperInfo.objects.filter(user_id=self.user_obj, is_actived=True,
use_number__lte=F("usable_number")).first().update(
use_number=self.developer_obj.use_number + 1)
developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=self.user_obj, is_actived=True,
use_number__lte=F("usable_number")).first()
developer_obj.use_number=self.developer_obj.use_number + 1
developer_obj.save()
# 生成新的ipa,然后替换release,或许,binary_file 这个字段已经无用
# AppReleaseInfo.objects.filter(app_id=self.app_obj,is_master=True).update(release_id=random_file_name)
del_cache_response_by_short(self.app_obj.short,self.app_obj.app_id,udid=self.udid_info.get('udid'))
#创建
apptodev_obj=APPToDeveloper.objects.filter(developerid=developer_obj,app_id=self.app_obj).first()
if apptodev_obj:
storage = Storage(self.user_obj)
storage.delete_file(apptodev_obj.binary_file, release_obj.release_type)
apptodev_obj.binary_file=random_file_name
apptodev_obj.save()
else:
APPToDeveloper.objects.create(developerid=developer_obj,app_id=self.app_obj,binary_file=random_file_name)
@staticmethod
def disable_udid(udid_obj,app_id):
usedeviceobj=APPSuperSignUsedInfo.objects.filter(udid=udid_obj,app_id_id=app_id)
if usedeviceobj:
developer_obj = usedeviceobj.first().developerid
@ -208,6 +233,153 @@ class IosUtils(object):
"password": developer_obj.password,
"certid": developer_obj.certid
}
# 需要判断该设备在同一个账户下 的多个应用,若存在,则不操作
udid_lists=APPSuperSignUsedInfo.objects.values_list("udid__udid").filter(developerid=developer_obj)
if len(udid_lists) == len(set(udid_lists)):
app_api_obj = AppDeveloperApi(**auth)
app_api_obj.set_device_status("disable",udid_obj.udid)
if developer_obj.use_number > 0:
developer_obj.use_number=developer_obj.use_number-1
developer_obj.save()
usedeviceobj.delete()
# 通过开发者id判断 app_id 是否多个,否则删除profile 文件
if APPSuperSignUsedInfo.objects.filter(developerid=developer_obj, app_id_id=app_id).count() == 0:
app_api_obj = AppDeveloperApi(**auth)
app_obj = Apps.objects.filter(pk=app_id).first()
app_api_obj.del_profile(app_obj.bundle_id,app_obj.app_id)
app_api_obj2 = AppDeveloperApi(**auth)
app_api_obj2.del_app(app_obj.bundle_id,app_obj.app_id)
APPToDeveloper.objects.filter(developerid=developer_obj,app_id_id=app_id).delete()
@staticmethod
def clean_udid_by_app_obj(app_obj):
for SuperSignUsed_obj in APPSuperSignUsedInfo.objects.filter(app_id=app_obj):
udid_obj = SuperSignUsed_obj.udid
developer_obj=SuperSignUsed_obj.developerid
auth = {
"username": developer_obj.email,
"password": developer_obj.password,
"certid": developer_obj.certid
}
# 需要判断该设备在同一个账户下 的多个应用,若存在,则不操作
udid_lists = APPSuperSignUsedInfo.objects.values_list("udid__udid").filter(developerid=developer_obj)
if len(udid_lists) == len(set(udid_lists)):
app_api_obj = AppDeveloperApi(**auth)
app_api_obj.set_device_status("disable", udid_obj.udid)
if developer_obj.use_number > 0:
developer_obj.use_number = developer_obj.use_number - 1
developer_obj.save()
udid_obj.delete()
SuperSignUsed_obj.delete()
@staticmethod
def clean_app_by_user_obj(app_obj,user_obj):
'''
该APP为超级签删除app的时候需要清理一下开发者账户里面的profile bundleid
:param app_obj:
:param user_obj:
:return:
'''
SuperSign_obj_lists=list(set(APPSuperSignUsedInfo.objects.values_list("developerid").filter(user_id=user_obj, app_id=app_obj)))
for SuperSign_obj in SuperSign_obj_lists:
developer_obj=AppIOSDeveloperInfo.objects.filter(pk=SuperSign_obj[0]).first()
if developer_obj:
IosUtils.clean_app_by_developer_obj(app_obj,developer_obj)
APPToDeveloper.objects.filter(developerid=developer_obj,app_id=app_obj).delete()
IosUtils.clean_udid_by_app_obj(app_obj)
@staticmethod
def clean_app_by_developer_obj(app_obj,developer_obj):
auth = {
"username": developer_obj.email,
"password": developer_obj.password,
"certid": developer_obj.certid
}
app_api_obj = AppDeveloperApi(**auth)
app_api_obj.del_profile(app_obj.bundle_id, app_obj.app_id)
app_api_obj2 = AppDeveloperApi(**auth)
app_api_obj2.del_app(app_obj.bundle_id,app_obj.app_id)
@staticmethod
def clean_developer(developer_obj):
'''
根据消耗记录 删除该苹果账户下所有信息
:param developer_obj:
:return:
'''
auth = {
"username": developer_obj.email,
"password": developer_obj.password,
"certid": developer_obj.certid
}
for SuperSignUsed_obj in APPSuperSignUsedInfo.objects.filter(developerid=developer_obj):
app_obj = SuperSignUsed_obj.app_id
app_api_obj = AppDeveloperApi(**auth)
app_api_obj.set_device_status("disable",udid_obj.udid)
usedeviceobj.delete()
app_api_obj.del_profile(app_obj.bundle_id, app_obj.app_id)
app_api_obj2 = AppDeveloperApi(**auth)
app_api_obj2.del_app(app_obj.bundle_id,app_obj.app_id)
APPToDeveloper.objects.filter(developerid=developer_obj, app_id=app_obj).delete()
@staticmethod
def active_developer(developer_obj,code=None):
'''
激活开发者账户
:param developer_obj:
:param code:
:return:
'''
auth = {
"username": developer_obj.email,
"password": developer_obj.password,
"certid": developer_obj.certid
}
app_api_obj = AppDeveloperApi(**auth)
return app_api_obj.active(code)
@staticmethod
def create_developer_cert(developer_obj,user_obj):
auth = {
"username": developer_obj.email,
"password": developer_obj.password,
"certid": developer_obj.certid
}
app_api_obj = AppDeveloperApi(**auth)
app_api_obj.create_cert(user_obj)
file_format_path_name = file_format_path(user_obj,auth)
cert_info = None
try:
with open(file_format_path_name + '.info', "r") as f:
cert_info = f.read()
except Exception as e:
print(e)
cert_id = re.findall(r'.*\n\tid=(.*),.*', cert_info)[0].replace('"', '')
developer_obj=AppIOSDeveloperInfo.objects.filter(user_id=user_obj, email=auth.get("username")).first()
developer_obj.is_actived=True
developer_obj.certid=cert_id
developer_obj.save()
def file_format_path(user_obj,auth):
cert_dir_name = make_app_uuid(user_obj, auth.get("username"))
cert_dir_path = os.path.join(SUPER_SIGN_ROOT, cert_dir_name)
if not os.path.isdir(cert_dir_path):
os.makedirs(cert_dir_path)
file_format_path_name = os.path.join(cert_dir_path, cert_dir_name)
return file_format_path_name

@ -0,0 +1,53 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 4月
# author: liuyu
# date: 2020/4/7
from apscheduler.schedulers.background import BackgroundScheduler
from django_apscheduler.jobstores import DjangoJobStore, register_events, register_job
from fir_ser.settings import SYNC_CACHE_TO_DATABASE
from api.utils.crontab.sync_cache import sync_download_times
# import atexit
# import fcntl
#
# # 主要是为了防止多进程出现的多个定时任务同时执行
# f = open("scheduler.lock", "wb")
# try:
# fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
# 开启定时工作
try:
# 实例化调度器
scheduler = BackgroundScheduler()
# 调度器使用DjangoJobStore()
scheduler.add_jobstore(DjangoJobStore(), "default")
# 设置定时任务,选择方式为interval,时间间隔为10s
# 另一种方式为每天固定时间执行任务,对应代码为:
# @register_job(scheduler, 'cron', day_of_week='mon-fri', hour='9', minute='30', second='10',id='task_time')
@register_job(scheduler, "interval", seconds=SYNC_CACHE_TO_DATABASE.get("download_times"))
def sync_download_times_job():
# 这里写你要执行的任务
sync_download_times()
register_events(scheduler)
scheduler.start()
except Exception as e:
print(e)
# 有错误就停止定时器
scheduler.shutdown()
#
# except:
# pass
#
#
# def unlock():
# fcntl.flock(f, fcntl.LOCK_UN)
# f.close()
#
#
# atexit.register(unlock)

@ -171,7 +171,7 @@ class AppReleaseSerializer(serializers.ModelSerializer):
icon_url=""
if self.context.get("storage", None) and self.context.get("storage") != "undefined":
storage = self.context.get("storage", None)
icon_url = storage.get_download_url(os.path.basename(obj.icon_url))
icon_url = storage.get_download_url(os.path.basename(obj.icon_url),600)
return icon_url
@ -217,7 +217,7 @@ class DeveloperSerializer(serializers.ModelSerializer):
class Meta:
model = models.AppIOSDeveloperInfo
# depth = 1
exclude = ["password", "id","name","user_id"]
exclude = ["password", "id","user_id"]
class SuperSignUsedSerializer(serializers.ModelSerializer):
class Meta:

@ -5,7 +5,7 @@
# date: 2020/4/7
from django.core.cache import cache
from api.models import Apps,UserInfo,AppReleaseInfo,AppUDID
from api.models import Apps,UserInfo,AppReleaseInfo,AppUDID,APPToDeveloper,APPSuperSignUsedInfo
import time,os
from django.utils import timezone
from fir_ser.settings import CACHE_KEY_TEMPLATE
@ -24,8 +24,19 @@ def get_download_url_by_cache(app_obj, filename, limit, isdownload=True,key='',u
else:
appudid_obj = AppUDID.objects.filter(app_id_id=app_obj.get("pk"),udid=udid,is_signed=True).first()
if appudid_obj:
filename=appudid_obj.binary_file+'.ipa'
return local_storage.get_download_url(filename, limit)
SuperSign_obj = APPSuperSignUsedInfo.objects.filter(udid__udid=udid,app_id_id=app_obj.get("pk")).first()
if SuperSign_obj:
APPToDeveloper_obj = APPToDeveloper.objects.filter(app_id_id=app_obj.get("pk"),developerid=SuperSign_obj.developerid).first()
if APPToDeveloper_obj:
filename=APPToDeveloper_obj.binary_file
return local_storage.get_download_url(filename, limit, download_url_type)
else:
return ""
else:
return ""
else:
return ""
return local_storage.get_download_url(filename, limit, download_url_type)
down_key = "_".join([key.lower(), CACHE_KEY_TEMPLATE.get('download_url_key'), filename])
download_val = cache.get(down_key)
@ -38,7 +49,9 @@ def get_download_url_by_cache(app_obj, filename, limit, isdownload=True,key='',u
return storage.get_download_url(filename, limit)
def get_app_instance_by_cache(app_id,password, limit):
def get_app_instance_by_cache(app_id,password, limit,udid):
if udid:
return Apps.objects.filter(app_id=app_id).values("pk", 'user_id', 'type','password','issupersign').first()
app_key="_".join([CACHE_KEY_TEMPLATE.get("app_instance_key"),app_id])
app_obj_cache = cache.get(app_key)
if not app_obj_cache:
@ -79,10 +92,11 @@ def del_cache_response_by_short(short,app_id,udid=''):
key='ShortDownloadView'.lower()
master_release_dict = AppReleaseInfo.objects.filter(app_id__app_id=app_id,is_master=True).values('icon_url','release_id').first()
download_val = CACHE_KEY_TEMPLATE.get('download_url_key')
cache.delete("_".join([key, download_val, os.path.basename(master_release_dict.get("icon_url")),udid]))
cache.delete("_".join([key,download_val, master_release_dict.get('release_id'),udid]))
cache.delete("_".join([key, CACHE_KEY_TEMPLATE.get("make_token_key"), master_release_dict.get('release_id'),udid]))
if master_release_dict:
download_val = CACHE_KEY_TEMPLATE.get('download_url_key')
cache.delete("_".join([key, download_val, os.path.basename(master_release_dict.get("icon_url")),udid]))
cache.delete("_".join([key,download_val, master_release_dict.get('release_id'),udid]))
cache.delete("_".join([key, CACHE_KEY_TEMPLATE.get("make_token_key"), master_release_dict.get('release_id'),udid]))
def del_cache_by_app_id(app_id,user_obj):

@ -11,10 +11,11 @@ from rest_framework.response import Response
from django.db.models import Sum
import os
from fir_ser import settings
from api.utils.app.supersignutils import IosUtils
from api.utils.app.randomstrings import make_from_user_uuid
from api.utils.storage.storage import Storage
from api.utils.storage.caches import del_cache_response_by_short,get_app_today_download_times
from api.models import Apps, AppReleaseInfo
from api.models import Apps, AppReleaseInfo,APPToDeveloper
from api.utils.serializer import AppsSerializer, AppReleaseSerializer, UserInfoSerializer
from rest_framework.pagination import PageNumberPagination
@ -107,6 +108,9 @@ class AppInfoView(APIView):
userserializer = UserInfoSerializer(request.user)
res.userinfo = {}
res.userinfo = userserializer.data
count=APPToDeveloper.objects.filter(app_id=apps_obj).count()
res.data["count"] = count
return Response(res.dict)
def delete(self, request, app_id):
@ -115,18 +119,16 @@ class AppInfoView(APIView):
apps_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first()
if apps_obj:
storage = Storage(request.user)
for appreleaseobj in AppReleaseInfo.objects.filter(app_id=apps_obj).all():
storage.delete_file(appreleaseobj.release_id, appreleaseobj.release_type)
storage.delete_file(appreleaseobj.icon_url)
appreleaseobj.delete()
has_combo = apps_obj.has_combo
if has_combo:
del_cache_response_by_short(apps_obj.has_combo.short,apps_obj.has_combo.app_id)
apps_obj.has_combo.has_combo = None
apps_obj.delete()
del_cache_response_by_short(apps_obj.short,apps_obj.app_id)
for appreleaseobj in AppReleaseInfo.objects.filter(app_id=apps_obj).all():
storage.delete_file(appreleaseobj.release_id, appreleaseobj.release_type)
storage.delete_file(appreleaseobj.icon_url)
appreleaseobj.delete()
apps_obj.delete()
return Response(res.dict)
@ -135,6 +137,12 @@ class AppInfoView(APIView):
if app_id:
data = request.data
clean = data.get("clean",None)
if clean :
apps_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first()
IosUtils.clean_app_by_user_obj(apps_obj,request.user)
return Response(res.dict)
has_combo = data.get("has_combo", None)
if has_combo:
actions = has_combo.get("action", None)
@ -309,7 +317,6 @@ class AppReleaseinfoView(APIView):
else:
binary_url = appreleaseobj.first().binary_url
print(binary_url)
appreleaseobj.update(**{"binary_url": binary_url})
except Exception as e:

@ -106,7 +106,13 @@ class ShortDownloadView(APIView):
def calculate_cache_key(self, view_instance, view_method,
request, args, kwargs):
release_id = request.query_params.get("release_id", '')
udid = request.query_params.get("udid", '')
udid = request.query_params.get("udid", None)
time = request.query_params.get("time", None)
if udid and time:
udid=time
if not udid:
udid=""
return "_".join([settings.CACHE_KEY_TEMPLATE.get("download_short_key"), kwargs.get("short", ''),release_id,udid])
class InstallView(APIView):
@ -130,9 +136,8 @@ class InstallView(APIView):
dtoken = DownloadToken()
if dtoken.verify_token(downtoken,release_id):
app_obj = get_app_instance_by_cache(app_id,password,900)
app_obj = get_app_instance_by_cache(app_id,password,900,udid)
if app_obj:
set_app_download_by_cache(app_id)
if app_obj.get("type") == 0:
apptype = '.apk'
download_url = get_download_url_by_cache(app_obj,release_id + apptype,600)
@ -144,6 +149,8 @@ class InstallView(APIView):
download_url = get_download_url_by_cache(app_obj,release_id + apptype,600,isdownload,udid=udid)
res.data={"download_url":download_url}
if download_url!= "":
set_app_download_by_cache(app_id)
return Response(res.dict)
else:
res.code = 1004

@ -32,6 +32,7 @@ class LoginView(APIView):
username = receive.get("username")
password = receive.get("password")
user = auth.authenticate(username=username, password=password)
print(username,password,user)
if user is not None:
if user.is_active:

@ -35,15 +35,73 @@ class DeveloperView(APIView):
app_page_serializer = page_obj.paginate_queryset(queryset=developer_obj.order_by("-updated_time"), request=request,
view=self)
app_serializer = DeveloperSerializer(app_page_serializer, many=True,)
Developer_serializer = DeveloperSerializer(app_page_serializer, many=True,)
userserializer = UserInfoSerializer(request.user)
res.userinfo = {}
res.has_next = {}
res.userinfo = userserializer.data
res.data = app_serializer.data
res.data = Developer_serializer.data
res.has_next = page_obj.page.has_next()
return Response(res.dict)
def put(self,request):
data = request.data
email=data.get("email",None)
if email:
developer_obj = AppIOSDeveloperInfo.objects.filter(user_id=request.user,email=email).first()
if developer_obj:
act = data.get("act", None)
if act:
res = BaseResponse()
if act == "preactive":
if not IosUtils.active_developer(developer_obj):
res.code = 1008
res.msg = "开发者账户或密码有误"
return Response(res.dict)
else:
res.code = 1009
return Response(res.dict)
elif act == "nowactive" :
code = data.get("code", None)
if code:
if IosUtils.active_developer(developer_obj,code):
developer_obj.is_actived=True
developer_obj.save()
IosUtils.create_developer_cert(developer_obj,request.user)
else:
developer_obj.usable_number=data.get("usable_number",developer_obj.usable_number)
developer_obj.description = data.get("description", developer_obj.description)
password = data.get("password", developer_obj.password)
if password != "" and password != developer_obj.password:
developer_obj.password=password
developer_obj.is_actived=False
developer_obj.save()
return self.get(request)
def post(self,request):
data = request.data
datainfo={
"usable_number" : data.get("usable_number", ""),
"description" : data.get("description", ""),
"password" : data.get("password", ""),
"email" : data.get("email", ""),
}
try:
AppIOSDeveloperInfo.objects.create(user_id=request.user,**datainfo)
except Exception as e:
print(e)
res = BaseResponse()
res.code=1005
res.msg="添加失败"
return Response(res.dict)
return self.get(request)
class SuperSignUsedView(APIView):
authentication_classes = [ExpiringTokenAuthentication, ]
@ -84,7 +142,6 @@ class AppUDIDUsedView(APIView):
return Response(res.dict)
def delete(self,request):
res = BaseResponse()
id = request.query_params.get("id", None)
app_id = request.query_params.get("aid", None)
app_udid_obj=AppUDID.objects.filter(app_id__user_id_id=request.user,pk=id)

@ -33,6 +33,8 @@ from api.views.captcha import CaptchaView
from django.views.static import serve
from fir_ser import settings
from api.views.download import DownloadView,InstallView
from api.views.receiveudids import IosUDIDView
urlpatterns = [
path('fly.admin/', admin.site.urls),
@ -49,4 +51,5 @@ urlpatterns = [
re_path(r'files/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
re_path("download/(?P<filename>\w+\.\w+)$", DownloadView.as_view(),name="download"),
re_path("install/(?P<app_id>\w+)$", InstallView.as_view(), name="install"),
re_path("^udid/(?P<short>\w+)$", IosUDIDView.as_view()),
]

@ -7,11 +7,14 @@ APScheduler==3.6.3
asgiref==3.2.3
asn1crypto==1.3.0
backcall==0.1.0
bcrypt==3.1.7
certifi==2019.11.28
cffi==1.14.0
chardet==3.0.4
Click==7.0
colorama==0.4.3
crcmod==1.7
cryptography==2.9.2
cycler==0.10.0
decorator==4.4.2
Django==3.0.3
@ -35,16 +38,19 @@ mysqlclient==1.4.6
networkx==2.4
numpy==1.18.1
oss2==2.9.1
paramiko==2.7.1
parso==0.6.2
pexpect==4.8.0
pickleshare==0.7.5
Pillow==7.0.0
prompt-toolkit==3.0.3
ptyprocess==0.6.0
pycparser==2.20
pycryptodome==3.9.7
pydot==1.4.1
Pygments==2.5.2
PyMySQL==0.9.3
PyNaCl==1.3.0
pyparsing==2.4.6
python-dateutil==2.8.1
pytz==2019.3

@ -50,11 +50,18 @@ class DevelopPortalHandle
profile = nil
if 0 < filtered_profiles.length then
profile = filtered_profiles[0]
all_devices = Spaceship::Portal.device.all
profile.devices=all_devices
profile.update!
profile = provisioningClass.find_by_bundle_id(bundle_id: appid)[0]
elsif 0 == filtered_profiles.length then
profile = createDistributionProvision(provisioningClass,appid,provisionName,certid)
end
#没有找到就创建,找到就下载
if profile.status == "Invalid" or profile.status == "Expired" then
profile.repair! # yes, that's all you need to repair a profile
end
File.write(provisionName, profile.download)
return provisionName
end
@ -150,6 +157,8 @@ end
handle.createCert(file_format_path_name)
end
when "active"
puts "active"
else
puts "error"
end

Loading…
Cancel
Save